2011-08-05 38 views
5

我在命令行中運行此一行代碼:爲什麼Perl在遞增後打印出我不期望的值?

perl -MList::Util=sum -E 'my $x = 0; say sum(++$x, ++$x)' 

爲什麼它說"4"代替"3"

+0

另請參見[什麼perl代碼示例可能導致未定義的行爲?](http://stackoverflow.com/questions/2176453/what-perl-code-samples-can-lead-to-undefined-behaviour) –

回答

4

你在同一個語句修改$x兩次。根據docs,Perl不能保證這個語句的結果是什麼。所以它可能相當於"2""0"

+0

文檔中的內容不相關。它說結果沒有被定義,因爲運算符的操作數評估順序沒有被定義。雖然'+'(在本例中使用)的確如此,但它不適用於逗號運算符(由OP使用)。逗號運算符*的LHS記錄在RHS之前進行評估。 – ikegami

+0

請注意,Perl在這種情況下也不能保證結果,但它是出於不同的原因。瞭解結果取決於知道預增量是否返回原始(現在已修改)的標量或其副本,並且* that *沒有記錄。 (這是前者,fyi。) – ikegami

3

因爲這兩個增量在計算總和之前執行。

兩者執行後,x = 2

2 + 2 = 4. 
+1

如果那麼'sum(++ $ x,++ $ x)'和'sum(0 + ++ $ x,0 + ++ $ x)'會產生相同的結果。 – ikegami

+1

@ikegami不正確,因爲表達式'++ $ x'具有左值本質,但表達式'0 ++ ++ $ x'具有右值性質。通常這是不相關的,因爲它們被用作rvalues,但是在未定義的情況下,在函數調用中做兩個預增量,它恰好具有早期vs晚期綁定ish效果。 – hobbs

+0

@hobbs,你說我說的不是真的,但你繼續同意我的觀點,即op的左值本質是真正的原因。這在我的答案中有詳細的介紹。 – ikegami

7

首先,請記住Perl通過引用傳遞。這意味着

sum(++$x, ++$x) 

是基本相同

do { 
    local @_; 
    alias $_[0] = ++$x; 
    alias $_[1] = ++$x; 
    ∑ 
} 

前遞增返回變量本身,而不是它的一個副本*,因此,這意味着既$_[0]$_[1]被化名爲$x。因此,sum可以看到兩個參數的當前值$x2)。

經驗法則:不要修改和讀取同一語句中的值。

* —這是沒有記錄,但你問爲什麼Perl行爲的方式。

+0

+1我想你的意思是輸入「$ x'(2)'」的當前值。 – FMc

+0

@FMc,謝謝,修正。 – ikegami

相關問題