到处都是,特别是在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),还是参数的上下文?
答案 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(),并将引用作为隐式的第一个参数。
编辑:两位评论者都是正确的。这个答案最初的目的是作为对已接受答案的评论。 (有没有办法解决这个问题?)
很抱歉这个混乱。我在这里添加了一些细节,希望它能更清楚地说明它与原始问题的关系(取消引用一个未定义的变量)。