我很难理解OO Perl和my $self = shift;
的交集这些单独元素的文档很棒,但我发现它们都没有触及它们的工作原理在一起。
我一直在使用Moose制作带有属性的模块,当然,在所述模块中引用模块的属性也很有用。我已经被一遍又一遍地告诉我在子程序中使用my $self = shift;
来将模块的属性分配给该变量。这是有道理和有效的,但是当我也将参数传递给子例程时,此过程显然采用@ARGV
数组的第一个元素,并将其分配给$self
。
有人可以解释我如何使用shift来获取对模块属性的内部访问权限,同时还传递@ARGV
数组中的参数吗?
答案 0 :(得分:58)
首先,子程序未通过@ARGV
数组。而是将传递给子例程的所有参数展平为子例程内@_
表示的单个列表。 @ARGV数组位于脚本的顶层,包含传递给脚本的命令行参数。
现在,在Perl中,当您在对象上调用方法时,该对象将作为参数隐式传递给方法。
如果忽略继承,
$obj->doCoolStuff($a, $b);
相当于
doCoolStuff($obj, $a, $b);
这意味着方法@_
中doCoolStuff
的内容将是:
@_ = ($obj, $a, $b);
现在,shift
内置函数(没有任何参数)将元素移出默认数组变量@_
。在这种情况下,那将是$obj
。
因此,当您执行$self = shift
时,您实际上是在说$self = $obj
。
我也希望这能解释如何通过->
表示法将其他参数传递给方法。继续我上面提到的例子,这就像:
sub doCoolStuff {
# Remember @_ = ($obj, $a, $b)
my $self = shift;
my ($a, $b) = @_;
此外,虽然Moose
是Perl的一个很棒的对象层,但它并没有消除您需要在每个方法中自己初始化$self
的要求。永远记住这一点。虽然像C ++和Java这样的语言隐式初始化对象引用this
,但在Perl中你需要为你编写的每个方法显式地执行它。
答案 1 :(得分:8)
在顶级代码中,shift()
是shift(@ARGV)
的缩写。 @ARGV
包含命令行参数。
在子版中,shift()
是shift(@_)
的缩写。 @_
包含sub的参数。
所以my $self = shift;
抓住了sub的第一个参数。调用方法时,调用者(->
的左侧)将作为第一个参数传递。换句话说,
$o->method(@a)
类似于
my $sub = $o->can('method');
$sub->($o, @a);
在该示例中,my $self = shift;
会将$o
分配给$self
。
答案 2 :(得分:2)
如果你打电话:
$myinstance->myMethod("my_parameter");
与做:
相同myMethod($myinstance, "my_parameter");
但如果你这样做:
myMethod("my_parameter");
仅限#34; my_parameter"将被通过。
然后如果你在myMethod里面总是这样做:
$self = shift @_;
当从对象上下文中调用myMethod id时,