2011-05-14 27 views

回答

7

@_參數數組的行爲不像您認爲的那樣。在子程序中的@_值實際上aliases for the real arguments

陣列@_是本地陣列,但它的元件是用於實際的標量參數的別名。

當你這樣說:

sub s { 
    "huh?" =~ /(.*)/; 
    print for @_; 
} 

"ok" =~ /(.*)/; 
s("$1", $1); 

中的第一個參數s$1立即被串插,但第二個參數評估不評估,它只是指出,在第二個值子版的@_$1(實際變量$1,而不是其值)。然後,在s內,$1的值由您的正則表達式更改。而現在,您的@_具有字符串"ok"的別名,後跟別名$1,這些別名在您的循環中由print解析。

如果更改的功能如下:

sub s { 
    my @a = @_; 
    "huh?" =~ /(.*)/; 
    print for @a; 
} 

,甚至這樣的:

sub s { 
    local $1; 
    "huh?" =~ /(.*)/; 
    print for @_; 
} 

然後你會得到兩行的「OK」,你期待。有趣的(有趣的獨特的,不好笑的哈哈)是s的這兩個版本出於不同的原因產生了預期的結果。my @a = @_;版本在正則表達式獲取之前提取@_中的別名的當前值$1;所述local $1; version本地化的$1變量到子離開別名@_從副外部引用的$1版本:

本地修改列出的變量是本地的封閉塊,文件,或EVAL。

怪異像這樣的,爲什麼你應該總是編號正則表達式捕獲變量的值複製到的變量儘快和你爲什麼要解開@_就在你的函數開始(除非你知道爲什麼你不想這樣做)。

希望我還沒有過多地使用術語,這是我一直遠離的那些怪異的Perl角色之一,因爲我不喜歡雜耍剃刀刀片。

2

的代碼使得使用兩個事實:

  • @_陣列的元件是用於實際的標量參數的別名。特別是,如果更新元素$_[0],則會更新相應的參數(反之亦然)。
  • $1是一個全局變量(雖然動態範圍爲當前BLOCK),它自動包含上次成功的模式匹配中的()的子模式。

子程序的第一個參數是普通字符串("ok")。第二個參數是全局變量$1。但是在打印參數之前,它由子例程內的成功模式匹配所改變。

1

發生這種情況是因爲perl通過引用傳遞參數。

你在做什麼是類似於:

my $a = 'ok'; 

sub foo { 
    $a = 'huh?'; 
    print for @_; 
} 

my $b = $a; 
foo($b, $a) 

當子FOO被調用時,$ _ [1]實際上是$一個,所以當$一個被修改它的值被修改的別名。