函式中什麼更好,每次需要時使用映射或將映射結果儲存在變數中並重新使用該變數?
我有一個將電子郵件(bytes32)連結到名為(uint256)的映射
emailToId
:mapping(bytes32 => uint256) public emailToId;
我的智能合約中也有使用此映射的函式,但我不知道哪個更好:
1 - 每次需要時使用映射
function changeUserNameAndEmail ( bytes32 email, bytes32 newName, bytes32 newEmail ) public { users[emailToId[email]].name = newName; emailToId[newEmail] = emailToId[email]; delete emailToId[email]; }
2 - 將映射結果儲存在一個變數中
userId
,並在每次需要時重新使用該變數function changeUserNameAndEmail ( bytes32 email, bytes32 newName, bytes32 newEmail ) public { uint256 userId = emailToId[email]; users[userId].name = newName; emailToId[newEmail] = userId; delete emailToId[email]; }
PS:這是一個簡單的例子,但有一些功能我需要使用 emailToId
$$ email $$幾次……我應該使用映射還是將其儲存在氣體成本和性能方面的變數中?
這有點棘手。
您所做的比較每種方法消耗的氣體的練習是要走的路。
通常,不需要
mapping
在記憶體中複製一個值。直接讀取和寫入它可能就足夠了。但有時,如果我們知道我們將讀取/寫入
mapping
多次,則在記憶體中複製該值可能很有用,也許我們只需要複製該值,對其執行許多操作,然後將其寫入一次到映射。特別是如果我們使用循環。請記住,在記憶體中複製一個值也需要消耗氣體,從 3 個氣體單位開始。複製的總成本將取決於您要複製的數據的大小。因此,有時我們可能不會從複製
memory
.如果您在這裡查看操作碼和它們消耗的氣體,您會注意到
MSTORE
(將值儲存在記憶體中)使用3*
氣體將數據儲存在記憶體中。這*
意味著它將取決於要複製的數據的大小。MLOAD
(從記憶體中讀取值)消耗相同的3*
.請注意,
SLOAD
使用 800 gas 從儲存中讀取一個字(32 個字節)。另請注意,SSTORE
用於20000*
將值儲存在儲存器中,具體取決於要保存的值,從 20000 單位的氣體開始。結論:
如果您不可避免地需要從 a
mapping
或儲存 x 次讀取並且您必須不可避免地再寫入mapping
x 次,那麼請考慮您是否真的需要在記憶體中製作副本,您可能不會這樣做。不要複製數據,
memory
除非您需要並且認為這樣做是有益的。因為如果不需要進行複制memory
,那麼您將浪費資源,因為您將在儲存中讀取/寫入,並且最重要的是在記憶體中製作數據的額外副本。有時它會很有用,有時它不會。比較這兩種方法,您可以選擇使用較少氣體的方法。使用循環時,檢查您是否多次修改同一個狀態變數,並決定是否應該更好地在 中創建一個副本
memory
,修改該副本,然後只用結果更新一次儲存。在此處檢查所有 EVM 操作碼和它們消耗的氣體:https ://github.com/crytic/evm-opcodes