2015-06-04 91 views
2

我的一位同事的說法,而不是一個分號後使用一個逗號,是什麼導致了類似到下面的代碼:語境和逗號運算符

my $SPECIAL_FIELD = 'd'; 
my %FIELD_MAP = (
    1 => 'a', 
    2 => 'b', 
    3 => 'c', 
); 

sub _translate_to_engine { 
    my ($href) = @_; 

    my %mapped_hash 
     = map { $FIELD_MAP{$_} => $href->{$_} } keys %$href; 

    $mapped_hash{$SPECIAL_FIELD} = FakeObject->new(
     params => $mapped_hash{$SPECIAL_FIELD} 
    ), # << comma here 

    return \%mapped_hash; 
} 

起初我很驚訝,這通過了perl -c,然後我想起了comma operator,並認爲我明白髮生了什麼事情,但下面的兩個打印語句的結果讓我再次懷疑。

my $scalar_return = _translate_to_engine( 
    { 1 => 'uno', 2 => 'dos', 3 => 'tres' } 
); 
print Dumper $scalar_return; 
# {'c' => 'tres','a' => 'uno','b' => 'dos','d' => bless({}, 'FakeObject')} 

這種呼籲在標量上下文,而我得到的是預期結果的結果做出。逗號運算符評估丟棄的逗號的LHS,然後評估RHS。我不認爲它可以在這裏返回RHS的值,因爲評估返回語句會留下子程序。

my @list_return = _translate_to_engine( 
    { 1 => 'uno', 2 => 'dos', 3 => 'tres' } 
); 
print Dumper \@list_return; 
# [{'c' => 'tres','a' => 'uno','b' => 'dos','d' => bless({}, 'FakeObject')}] 

這種呼籲在列表中作出,但結果我得到的是有效地等同於標量上下文呼叫。 我在這裏發生了什麼:因爲在列表上下文中調用了子進程,所以這兩個參數都會被計算,當RHS被評估時,return語句被執行,所以LHS被有效地丟棄。

任何情況下發生的具體語義澄清任何情況下,將不勝感激。

回答

1

您的解釋是正確的。

_translate_to_engine被調用的上下文影響是評估函數的所有最終表達式的上下文,包括所有return的參數。在這種情況下有兩個表達式受到影響:您提到的逗號和\%mapped_hash

在第一個測試中,返回值是\%mapped_hash在標量上下文中評估。第二,返回的值是在列表上下文中評估的\%mapped_hash。無論上下文如何,\%mapped_hash都評估爲對散列的引用。因此,無論上下文如何,子結果都是相同的。

+0

我相信我在我的倒數第二句話中說了類似於粗體文本的內容。感謝您提出關於上下文思考的觀點,我認爲它適用於所有內容。 –

+0

調整。你暗示你沒有得到預期的結果,但你沒有具體說明你期望的結果,所以我不確定需要解釋什麼。 – ikegami

+0

子中的許多內容不受子調用的上下文影響。例如,對'%mapped_hash'的賦值在void上下文中計算,並且'$ _'都是在標量上下文中計算的。 – ikegami

0

表達式的LHS是$mapped_hash{$SPECIAL_FIELD} = FakeObject->new(...)而RHS是return \%mapped_hash。正如你所說,逗號運算符評估左手邊(將一個FakeObject實例分配給散列鍵d),然後評估右手邊,導致該子程序返回hashref。我感覺合理。

在列表或標量上下文中調用子項並不重要。它不會改變逗號運算符的上下文,這兩種情況都是相同的。