當在列表語境中呼叫雜湊時,會傳回一個由雜湊下一個元素的鍵和值組成的 2 元素列表。僅在 Perl 5.12 和更新版本中,它也會傳回陣列下一個元素的索引和值,以便您可以反覆運算它;較舊的 Perl 會將此視為語法錯誤。當在標量語境中呼叫時,僅會傳回雜湊中的鍵(而非值),或陣列中的索引。
雜湊項目會以看似隨機的順序傳回。實際的隨機順序會針對特定雜湊而有所不同;對兩個雜湊執行完全相同的運算系列可能會產生不同的順序。任何插入雜湊的動作都可能變更順序,任何刪除動作也會變更順序,但例外情況是 each
或 keys
傳回的最新鍵可以在不變更順序的情況下刪除。只要給定的雜湊未修改,您就可以依賴 keys
、values
和 each
重複傳回與彼此相同的順序。請參閱 perlsec 中的「演算法複雜度攻擊」,以了解雜湊順序為何會隨機化的詳細資訊。除了這裡提供的保證之外,Perl 雜湊演算法和雜湊遍歷順序的確切詳細資訊可能會在任何 Perl 版本中變更。
在 each
從雜湊或陣列傳回所有項目後,下一次呼叫 each
會在列表語境中傳回空列表,在標量語境中傳回 undef
;接下來的呼叫會重新開始反覆運算。每個雜湊或陣列都有其自己的內部反覆運算器,可透過 each
、keys
和 values
存取。當 each
已如上所述到達結尾時,反覆運算器會隱式重設;您可以透過對雜湊或陣列呼叫 keys
或 values
,或在列表語境中參照雜湊(但非陣列)來明確重設它。如果您在反覆運算雜湊時新增或刪除其元素,對反覆運算器的影響是不確定的;例如,項目可能會被略過或重複,因此請勿執行此動作。例外:刪除 each
最近傳回的項目永遠是安全的,因此下列程式碼可以正常運作
while (my ($key, $value) = each %hash) {
print $key, "\n";
delete $hash{$key}; # This is safe
}
綁定的雜湊可能與 Perl 的雜湊實作有不同的排序行為。
each
使用的迭代器附加到雜湊或陣列,並在套用至同一個雜湊或陣列的所有迭代操作中共享。因此,在單一雜湊或陣列上使用 each
會推進同一個迭代器位置。所有使用 each
的情況也會受到在同一個雜湊或陣列上使用 keys
或 values
,或在清單內容中參照雜湊(但非陣列)時,迭代器重設的影響。這使得基於 each
的迴圈相當脆弱:很容易在迭代器已部分處理物件時到達此類迴圈,或是在執行迴圈主體時意外地破壞迭代器狀態。在開始迴圈前明確重設迭代器相當容易,但沒有辦法將迴圈使用的迭代器狀態與迴圈主體執行期間可能執行的其他任何元件使用的迭代器狀態隔離。若要避免這些問題,請使用 foreach
迴圈,而非 while
-each
。
這延伸至在匿名雜湊或陣列建構函式的結果上使用 each
。每次都會建立新的底層陣列或雜湊,因此每次都會從頭開始迭代,例如
# loops forever
while (my ($key, $value) = each @{ +{ a => 1 } }) {
print "$key=$value\n";
}
這會列印出您的環境,就像 printenv(1) 程式一樣,但順序不同
while (my ($key,$value) = each %ENV) {
print "$key=$value\n";
}
從 Perl 5.14 開始,一個實驗性功能允許 each
採用一個純量表達式。此實驗已被視為不成功,並已從 Perl 5.24 中移除。
從 Perl 5.18 開始,您可以在 while
迴圈中使用一個單獨的 each
,這會在每次迭代時設定 $_
。如果 each
表達式或將 each
表達式明確指定給一個純量的動作用作 while
/for
條件,則條件實際上會測試表達式值的定義性,而非其常規真值。
while (each %ENV) {
print "$_=$ENV{$_}\n";
}
若要避免讓使用較早版本 Perl 的程式碼潛在使用者因神秘的語法錯誤而感到困惑,請將此類內容放在檔案頂端,以表示您的程式碼僅適用於較新版本的 Perl
use v5.12; # so keys/values/each work on arrays
use v5.18; # so each assigns to $_ in a lone while test