任何人都可以在Perl中解释(我的$ self = shift)

Ale*_*dik 29 perl attributes self moose shift

我很难理解OO Perl的交集.my $self = shift;关于这些单独元素的文档很棒,但是我发现它们都没有触及它们如何协同工作.

我一直在使用Moose来创建具有属性的模块,当然,在所述模块中引用模块的属性是有用的.我一遍又一遍地被告知要my $self = shift;在子程序中使用将模块的属性分配给该变量.这是有道理和有效的,但是当我也将参数传递给子例程时,这个过程显然需要@ARGV数组的第一个元素并将它分配给它$self.

有人可以解释我如何使用shift来获取模块属性的内部访问权限,同时还传入@ARGV数组中的参数?

Nik*_*hil 59

首先,子程序不通过@ARGV数组.而是将传递给子例程的所有参数展平为@_子例程内部表示的单个列表.@ARGV数组位于脚本的顶层,包含传递给您脚本的命令行参数.

现在,在Perl中,当您在对象上调用方法时,该对象将作为参数隐式传递给方法.

如果忽略继承,

 $obj->doCoolStuff($a, $b);
Run Code Online (Sandbox Code Playgroud)

相当于

 doCoolStuff($obj, $a, $b);
Run Code Online (Sandbox Code Playgroud)

这意味着内容@_的方法doCoolStuff是: @_ = ($obj, $a, $b);

现在,shift内置函数(没有任何参数)将元素移出默认数组变量@_.在这种情况下,那将是$obj.

所以当你这样做时$self = shift,你实际上在说$self = $obj.

我也希望这解释了如何通过->符号将其他参数传递给方法.继续我上面提到的例子,这将是:

sub doCoolStuff {
  # Remember @_ = ($obj, $a, $b)
  my $self = shift;
  my ($a, $b) = @_;
Run Code Online (Sandbox Code Playgroud)

此外,虽然MoosePerl是一个很棒的对象层,但它并没有消除您需要$self在每个方法中初始化自己的要求.永远记住这一点.虽然像C++和Java这样的语言this隐式初始化对象引用,但在Perl中,您需要为您编写的每个方法显式地执行此操作.

  • 如果从子程序内部调用,`shift`默认为`@ _`,如果从顶级代码调用,则调用`@ ARGV`. (2认同)
  • @AlexHHadik我能想象只有一种情况会发生这样的事情。当您没有像这样通过对象调用方法时:“$obj->method($arg1, $arg2)”,您会错过该对象并直接调用该方法“method($arg1, $arg2)”。这在 Perl 中是完全合法的,因为方法调用与普通函数调用没有什么不同。但由于您没有使用“->”运算符通过对象调用它,因此“$obj”参数不会传递给 arg 列表中的方法。 (2认同)

ike*_*ami 8

在顶级代码中,shift()是简称shift(@ARGV).@ARGV包含命令行参数.

在一个子,shift()是短的shift(@_).@_包含sub的参数.

所以my $self = shift;抓住子的第一个论点.调用方法时,调用者(左边的内容->)作为第一个参数传递.换一种说法,

$o->method(@a)
Run Code Online (Sandbox Code Playgroud)

类似于

my $sub = $o->can('method');
$sub->($o, @a);
Run Code Online (Sandbox Code Playgroud)

在该示例中,my $self = shift;将分配$o$self.