30

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

我一直在使用 Moose 制作具有属性的模块,当然,在所述模块中引用模块的属性很有用。我一再被告知要my $self = shift;在子例程中使用将模块的属性分配给该变量。这很有意义并且有效,但是当我也将参数传递给子例程时,这个过程显然会获取@ARGV数组的第一个元素并将其分配给它$self

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

4

3 回答 3

63

首先,子程序没有传递给@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 中,您需要为您编写的每个方法显式地进行初始化。

于 2013-10-03T14:33:32.763 回答
8

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

在一个子中,shift()是 的缩写shift(@_)@_包含 sub 的参数。

my $self = shift;抓住潜艇的第一个论点也是如此。调用方法时,调用者(剩下的->)作为第一个参数传递。换句话说,

$o->method(@a)

类似于

my $sub = $o->can('method');
$sub->($o, @a);

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

于 2013-10-03T14:43:52.063 回答
2

如果你打电话:

$myinstance->myMethod("my_parameter");  

是一样的:

myMethod($myinstance, "my_parameter");  

但如果你这样做:

myMethod("my_parameter");  

只有“my_parameter”会被传递。

那么如果在 myMethod 中你总是这样做:

 $self = shift @_;  

当从对象上下文调用 myMethod id 时,$self 将是对象引用,但当
以程序方式从内部的另一个方法调用时,它将是“my_parameter”。
请注意这一点;

于 2014-03-03T00:19:02.083 回答