Solidity
使用映射作為臨時 KeyValue 實例是否方便?
考慮以下說明問題的契約。這裡我們有一個動態映射數組,
add()
意在向數組末尾添加一個新的映射,返回映射鍵的值並將該值0
更改為true
.remove()
反過來意味著從數組中刪除最後一個映射。contract ClearMapping { mapping(uint => bool)[] state; // 1. add -> false // 2. remove // 3. add -> true function add() returns (bool) { uint pos = state.length++; bool curr = state[pos][0]; state[pos][0] = true; return curr; } function remove() { state.length--; } }
可以認為從數組中刪除映射元素有效地清除了該映射,並且添加一個新映射代替舊映射將有一個新的 all
key* -> false
元素。事實證明這不是真的。如果您嘗試交換內部具有映射的元素,也會發生同樣的事情,除了映射之外的所有內容都將被交換。我看到的唯一解決方案是手動刪除/重新分配每個使用的映射鍵,但它在氣體使用方面變得非常昂貴。
我要回答的問題是:
- 這是 EVM/Solidity 中的錯誤嗎?
- 是否有一種方便/有效的方法來清除/交換映射?
- 我不應該將映射用作臨時 KeyValue 實例嗎?
感謝關注!
為了回答你的問題,讓我解釋一下 EVM 堆棧的實際樣子:它本身只是一個從鍵到值的映射,都是 32 字節長。
一個可靠映射,從 sha3(mapId . key) 映射到 evm 堆棧上的給定值。這也是無法遍歷映射中所有鍵的原因,因為它們在整個 evm 堆棧中是“隨機化的”。
一個solidity數組從sha3(arrayId)+索引映射到一個值。如果我們只通過增加索引來知道arrayId,我們就可以在這裡進行迭代。
(這裡我不確定是否也保存了數組的長度。)
以下只是推測,因為我完全確定solidity如何解決這個問題:如果您現在有一個地圖數組,那麼您實際上要做的是mapId = sha3(arrayId)+ index。您可以遍歷它們。但是,如果您將某些內容保存到地圖中,請執行以下操作:
sha3((sha3(arrayId) + index) . key ) = value
但是通過刪除映射的最後一個元素,您會失去映射的數組 id,但是因為在不知道鍵的情況下無法遍歷映射,因此您的值會被保留。
但是,多數組沒有這個問題:
import "dapple/test.sol"; contract A is Test { uint[][] multiarray; function testMultiArray() { //@log multiarray length: `uint multiarray.length` //@log incrementing multiarray multiarray.length++; //@log multiarray length: `uint multiarray.length` //@log multiarray[0] length: `uint multiarray[0].length` //@log incrementing multiarray[0] multiarray[0].length++; multiarray[0].length++; //@log multiarray[0][0]: `uint multiarray[0][0]` //@log set value to 1 multiarray[0][0] = 1; multiarray[0][1] = 1; //@log multiarray[0] length: `uint multiarray[0].length` //@log multiarray[0][0]: `uint multiarray[0][0]` //@log multiarray[0][1]: `uint multiarray[0][1]` //@log decrementing multiarray multiarray.length--; //@log multiarray[0] length: `uint multiarray.length` //@log incrementing multiarray multiarray.length++; //@log multiarray[0] length: `uint multiarray[0].length` multiarray[0].length++; multiarray[0].length++; //@log multiarray[0][0]: `uint multiarray[0][0]` //@log multiarray[0][1]: `uint multiarray[0][1]` } }
將產生以下輸出:
test multi array LOG: multiarray length: 0 LOG: incrementing multiarray LOG: multiarray length: 1 LOG: multiarray[0] length: 0 LOG: incrementing multiarray[0] LOG: multiarray[0][0]: 0 LOG: set value to 1 LOG: multiarray[0] length: 2 LOG: multiarray[0][0]: 1 LOG: multiarray[0][1]: 1 LOG: decrementing multiarray LOG: multiarray[0] length: 0 LOG: incrementing multiarray LOG: multiarray[0] length: 0 LOG: multiarray[0][0]: 0 LOG: multiarray[0][1]: 0