Perl 模块方法调用:无法调用方法“X” ${SOMEFILE} 行 ${SOMELINE} 处的未定义值

发布于 2024-09-16 15:00:47 字数 935 浏览 4 评论 0原文

在所有地方,尤其是在 DBI 中,我总是看到此消息出现。这很令人困惑,因为首先想到的是我传递给函数的参数被设置为 undef (或类似的东西),但显然情况并非如此。

给定一个模块和相应的脚本...

模块:./lib/My/Module.pm

package My::Module;

use strict;
use warnings;

sub trim {
    my $str = shift;
    $str =~ s{ \A \s+ }{}xms; # remove space from front of string
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string
    return $str;
}

脚本:./test.pl

#!/usr/bin/perl

use strict;
use warnings;
use My::Module qw(trim);

print $My::Module->trim( " \t hello world\t \t" );

我收到错误消息

无法对 ./text.pl 第 7 行的未定义值调用方法“trim”。

事实上,如果我调用 $My::Module->notamethod( "hello world" ); 它给出了类似的错误。

上面的脚本/模块有什么问题?

这个错误 Can't call method “X” on an undefined value at ${SOMEFILE} line ${SOMELINE} 到底在说什么? 这是指方法调用的上下文(在此处传递给打印),还是参数的上下文?

All over the place, especially in DBI, I see this message come up all the time. It's confusing, because the first thing that comes to mind is that the arguments I'm passing the function are set to undef (or something similar), but it's clearly not the case.

Given a module and a corresponding script...

Module: ./lib/My/Module.pm

package My::Module;

use strict;
use warnings;

sub trim {
    my $str = shift;
    $str =~ s{ \A \s+ }{}xms; # remove space from front of string
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string
    return $str;
}

Script: ./test.pl

#!/usr/bin/perl

use strict;
use warnings;
use My::Module qw(trim);

print $My::Module->trim( " \t hello world\t \t" );

I get back the error message

Can't call method "trim" on an undefined value at ./text.pl line 7.

Infact, if I call $My::Module->notamethod( "hello world" ); it gives a similar error.

What's wrong with the above script/module?

What is that error Can't call method “X” on an undefined value at ${SOMEFILE} line ${SOMELINE} really saying?
Does this refer to the context of the method call (passed here to print), or the context of the arguments?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

饮惑 2024-09-23 15:00:47

您将几种不同的方法混为一谈来处理模块和对象,并最终得到一种不起作用的方法。

以下是四种可行的方法:

1/ My::Module 是一个库。修剪不导出。

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

sub trim {
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

# Note: No $ and :: not ->
print My::Module::trim( " \t hello world\t \t" );

2/ My::Module 是一个库。修剪已导出。

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

use Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(trim);

sub trim {
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

print trim( " \t hello world\t \t" );

3/ MyModule 是一个类。修剪是一个类方法。

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

sub trim {
  # Note class name passed as first argument
  my $class = shift;
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

# Note: Not $ and -> not ::
print My::Module->trim( " \t hello world\t \t" );

4/ MyModule 是一个类,trim 是一个对象方法。

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

# Need a constructor (but this one does nothing useful)
sub new {
  my $class = shift;

  return bless {}, $class;
}

sub trim {
  # Note: Object method is passed an object (which is ignored here)
  my $self = shift;
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

my $trimmer = My::Module->new;

print $trimmer->trim( " \t hello world\t \t" );

我认为您正在尝试选项 1。在这种情况下,我想我会推荐选项 2。

并回答您的最后一个问题。您收到该错误是因为您尝试调用未定义的变量 ($My::Module) 上的方法。

You're conflating several different ways to handle modules and objects - and ending up with one that doesn't work.

Here are four approaches that do work:

1/ My::Module is a library. trim is not exported.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

sub trim {
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

# Note: No $ and :: not ->
print My::Module::trim( " \t hello world\t \t" );

2/ My::Module is a library. trim is exported.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

use Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(trim);

sub trim {
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

print trim( " \t hello world\t \t" );

3/ MyModule is a class. trim is a class method.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

sub trim {
  # Note class name passed as first argument
  my $class = shift;
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

# Note: Not $ and -> not ::
print My::Module->trim( " \t hello world\t \t" );

4/ MyModule is a class, trim is an object method.

$ cat My/Module.pm 
package My::Module;

use strict;
use warnings;

# Need a constructor (but this one does nothing useful)
sub new {
  my $class = shift;

  return bless {}, $class;
}

sub trim {
  # Note: Object method is passed an object (which is ignored here)
  my $self = shift;
  my $str = shift;

  $str =~ s{ \A \s+ }{}xms; # remove space from front of string
  $str =~ s{ \s+ \z }{}xms; # remove space from end of string
  return $str;
}

1;
$ cat test 
#!/usr/bin/perl

use strict;
use warnings;

use My::Module;

my $trimmer = My::Module->new;

print $trimmer->trim( " \t hello world\t \t" );

I think that you were trying for option 1. In this case, I think I'd recommend option 2.

And to answer your final question. You are getting that error because you are trying to call a method on a variable ($My::Module) which is undefined.

卖梦商人 2024-09-23 15:00:47

该语法正在变量 $My::Module 中查找对象或类名并调用其修剪方法,但该变量未定义。

相反,您只需说 print My::Module::trim( " \t hello world\t \t" ); 即可调用 My::Module::trim() 函数。

从 use 行来看,您似乎正在尝试将 trim() 导入本地包,因此您可以在没有 My::Module:: 限定的情况下调用它,但您的模块看起来并不就像它是为了支持导出而设置的一样。

在您的正则表达式中, /s 和 /m 标志没有任何效果 - 它们只会更改 .、^ 和 $ 匹配的内容,并且您不使用其中任何一个。

That syntax is looking for an object or classname in the variable $My::Module and calling its trim method, but that variable is undefined.

Instead, you want to just say print My::Module::trim( " \t hello world\t \t" ); to call the My::Module::trim() function.

From the use line, it looks like you are trying to import trim() into the local package so you can just call it without the My::Module:: qualification, but your module doesn't look like it is set up to support exporting.

In your regexes, the /s and /m flags don't have any effect - they only change what ., ^, and $ match, and you don't use any of those.

所有深爱都是秘密 2024-09-23 15:00:47

这正是 Perl 进行面向对象的方式。区别在于调用方法的方式不同。

这只是调用 My::Module 包中的trim sub:

 My::Module::trim('foo')

另一方面,

 My::Module->trim('foo)

自动调用 My::Module 包中的trim sub,并以字符串“My::Module”作为第一个参数。
对象的工作方式相同:

 my $m = My::Module->new; # Corrected. Thanks for pointing this out.
 $m->trim('foo');

变成对同一个 sub 的调用,但这次将对 $m 对象的引用作为第一个参数。

您想要做的是:

$My::Module->trim('foo');

这会转换为变量 $My::Module (不存在)的取消引用,因此出现错误消息“无法在未定义的值上调用方法 X”。如果 $My::Module 是对对象的实际引用,则这将导致对该对象调用 trim() ,并将该引用作为隐式第一个参数。

编辑:两位评论者都是正确的。该答案最初旨在作为对已接受答案的评论。 (有办法解决这个问题吗?)

很抱歉造成混乱。我在这里添加了更多细节,因此希望它与原始问题的关系变得更清楚(取消引用未定义的变量)。

It is just how Perl does OO. The difference is in between the way you call the methods.

This just calls the trim sub in the My::Module package:

 My::Module::trim('foo')

On the other hand,

 My::Module->trim('foo)

automatically becomes a call to the trim sub in the My::Module package with the string "My::Module" as the first argument.
Objects work the same way:

 my $m = My::Module->new; # Corrected. Thanks for pointing this out.
 $m->trim('foo');

Turns into a call to the same sub, but this time with a reference to the $m object as the first argument.

What you are trying to do is:

$My::Module->trim('foo');

Which translates to a dereference of the variable $My::Module (which does not exist), thus the error message "Can't call method X on an undefined value". If $My::Module were an actual reference to an object, this would result in a call to trim() on that object, with the reference as an implicit first argument.

Edit: Both commenters are correct. This answer was originally intended as a comment to the accepted answer. (Is there a way to fix that?)

Sorry for the confusion. I've added a little more detail here so hopefully it becomes more clear how it relates to the original question (dereferencing an undefined variable).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文