2013-10-03 87 views
24

我很難理解OO Perl和my $self = shift;的交集關於這些單獨元素的文檔非常棒,但是我沒有發現他們關於它們如何一起工作的文檔。

我一直在使用Moose來創建具有屬性的模塊,當然這對於在模塊中引用模塊的屬性很有用。我一再被告知在子程序中使用my $self = shift;將模塊的屬性分配給該變量。這是有道理的,但是當我也將參數傳遞給子例程時,這個過程顯然需要@ARGV數組的第一個元素,並將它分配給$self

有人可以提供一個解釋,說明如何使用shift來獲得對模塊屬性的內部訪問,同時還在@ARGV數組中傳入參數?

回答

52

首先,子程序未通過@ARGV陣列。而是傳遞給子例程的所有參數都被平鋪到子例程中的@_表示的單個列表中。 @ARGV數組在您腳本的頂層可用,包含傳遞給您腳本的命令行參數。

現在,在Perl中,當您在對象上調用某個方法時,該對象將作爲參數隱式傳遞給該方法。

如果忽略繼承,

$obj->doCoolStuff($a, $b); 

相當於

doCoolStuff($obj, $a, $b); 

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

現在,shift內置函數,沒有任何參數,將元素移出d默認數組變量@_。在這種情況下,那將是$obj

所以,當你做$self = shift,你有效地說$self = $obj

我也希望這解釋瞭如何通過->表示法將其他參數傳遞給方法。繼續我上面所陳述的例子,這將是這樣的:

sub doCoolStuff { 
    # Remember @_ = ($obj, $a, $b) 
    my $self = shift; 
    my ($a, $b) = @_; 

此外,雖然Moose是Perl的一個偉大的對象層,它不會從你需要自己初始化$self要求帶走在每種方法中。永遠記住這一點。儘管像C++和Java這樣的語言隱式地初始化了對象引用this,但在Perl中,您需要明確地爲您編寫的每種方法執行此操作。

+2

如果從子例程內調用'shift_',默認爲'@ _',如果從頂級代碼調用''ARGV'',則默認爲'__'。 – cjm

+0

@cjm你是對的。將在答案中提到這一點。 – Nikhil

+0

太棒了。這非常有幫助。我遇到了一個問題,我的$ self = shift似乎將自己設置爲實際傳遞給子例程的第一個參數。也就是說,@_中的第一個元素不是對象,但實際上是我提供的第一個參數。這會發生什麼高水平的原因? (我解決了這個問題,並且沒有實際的代碼) –

8

在頂級密碼中,shift()shift(@ARGV)的簡稱。 @ARGV包含命令行參數。

在一個分類中,shift()shift(@_)的簡稱。 @_包含子的參數。

所以my $self = shift;抓住了子的第一個參數。當調用方法時,調用者(->的左側)作爲第一個參數傳遞。換句話說,

$o->method(@a) 

類似於

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

在該示例中,my $self = shift;將分配給$o$self

2

如果您撥打:

$myinstance->myMethod("my_parameter"); 

是一樣的,這樣做:

myMethod($myinstance, "my_parameter"); 

,但如果你這樣做:

myMethod("my_parameter"); 

只有 「my_parameter」 西港島線進行傳遞。

那麼如果裏面myMethod的總是你:

$self = shift @_; 

$自我將是對象的引用時,從對象上下文中調用myMethod的ID
,但會「my_parameter」從另一種方法在內部調用時程序方式。
請注意這一點;