智能合約開發

映射

映射是 Solidity 的雜湊表:它把鍵連結到值,就像把一個地址轉成餘額的字典。特別之處在於你從來不需要「新增」鍵。概念上每一個可能的鍵都早已對應到該型別的零值,而寫入某個鍵只是覆蓋那個預設值。所以一個剛部署的 mapping(address => uint256) 已經「擁有」全部 2^160 個地址的餘額 0;你能做的只是去改動其中一些。

底層其實根本沒有一張表。對於宣告在儲存槽 p 的映射,鍵 k 的值存放在儲存位置 keccak256(h(k) . p),其中 h(k) 是把鍵補滿成 32 位元組、再與 32 位元組的槽號串接後做雜湊。由於每筆項目都被散落到一個由雜湊推導出的槽位,而 EVM 無法反推 keccak-256,因此根本沒有一份「曾用過哪些鍵」的清單。這正是映射沒有長度、無法迭代、也無法整批刪除的原因。

實務後果是:你無法列舉映射、無法回傳它、也無法把它放進 memory 或 calldata——它只存在於 storage。若需要迭代,請在旁邊另外維護一個鍵的陣列(OpenZeppelin 的 EnumerableMap 就是自動化這個模式)。巢狀映射會遞迴雜湊(內層的槽位成為外層鍵的值位置)。讀取一個從未寫過的鍵不會出錯,而是默默回傳零值,因此要判斷「這個鍵存在嗎?」通常需要在值裡額外放一個布林旗標。

mapping(address => uint256) balances;
// balances[alice] lives at:
// keccak256(abi.encode(alice) . slotOfBalances)

沒有表、沒有鍵清單——每筆項目都隔著一次雜湊。

讀取未設定的鍵會回傳零值,而非回滾。沒有內建方式可區分「鍵不存在」與「鍵被設為零」——若需要區別,請另存一個明確的 exists 旗標。