今天,當我在 perl 中遇到以下行為時,我感到很驚訝:
sub f { die if %{ $_[0] }; 42 }
my %h;
$h{x} ||= f(\%h); # we die. $_[0] references a hash with an 'x' key during f's run-time
相反,給定相同的設定,以下陳述句的行為有所不同。
$h{x} = $h{x} || f(\%h); # $h{x} is now 42
分配或與分配和邏輯或記錄的組合之間的這種潛在差異是否在某處記錄?
如果這是由于自動激活,是否是autovivification模塊中的錯誤或缺失功能似乎無法檢測到此特定構造中的自動激活?
uj5u.com熱心網友回復:
關鍵資訊:
||并且||=是短路的,所以他們必須先評估他們的左側,然后再評估他們的右側。(這允許f() || die()。)=在其左側之前評估其右側運算元。(這允許$x = f($x)。)的左側
||=只計算一次。除非必要(即在左值背景關系中),否則不會在訪問時激活(創建)哈希元素。
我們來看看$h{x} = $h{x} || f(\%h);。
綜上所述,我們得出以下結論:
- 只有最左邊的
$h{x}需要激活元素。 - 最左邊的
$h{x}在f回傳后進行評估。
我們來看看$h{x} ||= f(\%h);。
綜上所述,我們得出以下結論:
$h{x}必須在呼叫 之前評估f。- Evaluating
$h{x}必須產生一個可修改的值,所以它必須 vivify$h{x}。
左值背景關系
- 賦值運算子的左側(包括
||=)。 - 前/后自增/自減的運算元。
- 的運算元
\。 - Foreach 回圈串列運算式(因為
$_ = uc($_) for @a;)。 - 子程式引數(因為
sub ucip { $_[0] = uc($_[0]) }),但請參閱下面的“一個例外”。 - 其他的?
一例外
如果你傳遞$h{x}給一個 sub,Perl 實際上傳遞了一個神奇的標量,它是代理$h{x}。如果可能的話,這樣做是為了防止復活。它并不便宜,但它避免了很多令人討厭的驚喜。
Perl 有可能在$h{x} ||= f(\%h);使用相同的機制時延遲激活,但不值得為此付出代價。
uj5u.com熱心網友回復:
事實上,僅僅檢查一個鍵并不能自動激活它
perl -Mstrict -wE'my %h; if ($h{k}) { say "yes" }; say "Exists" if exists $h{k}'
什么都不列印;密鑰k尚未添加到哈希中。(需要更多的自動激活,例如測驗嵌套鍵——然后必須創建通向最后一個鍵的鍵。)
這兩種情況在這個意義上不同,因為用||=了$h{x}被分配給子時f運行?等關鍵x必須為此轉讓的目的首先創建,而在其他情況下,$h{x}僅僅是被分前檢查f運行,所以沒有自動活化發生。
我不知道 的實際實作,||=也沒有在檔案中找到任何具體的宣告。
?該||=被列為賦值運算子
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/366775.html
上一篇:多重繼承-選擇了錯誤的多載
