Perl模块方法调用:不能在$ {SOMEFILE}行$ {SOMELINE}的未定义值上调用方法“X”

时间:2010-08-30 03:03:14

标签: perl function module dbi

到处都是,特别是在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}真的在说什么? 这是指方法调用的上下文(在这里传递给print),还是参数的上下文?

3 个答案:

答案 0 :(得分:13)

你正在混淆几种不同的方法来处理模块和对象 - 并最终得到一个不起作用的方法。

以下四种方法可行:

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是一个类。 trim是一种类方法。

$ 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)上调用方法。

答案 1 :(得分:6)

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

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

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

在你的正则表达式中,/ s和/ m标志没有任何效果 - 它们只改变。,^和$匹配,并且你不使用任何这些。

答案 2 :(得分:-1)

这就是Perl如何做OO。区别在于你调用方法的方式。

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

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

另一方面,

 My::Module->trim('foo)

自动成为对My :: Module包中trim子的调用,并将字符串“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(),并将引用作为隐式的第一个参数。

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

很抱歉这个混乱。我在这里添加了一些细节,希望它能更清楚地说明它与原始问题的关系(取消引用一个未定义的变量)。