Solidity
為什麼 Solidity Compiler 允許在函式內聲明儲存變數?
Solidity 不會導致此程式碼的任何編譯錯誤,儘管聲明儲存變數數據時未引用實際儲存(最初)
contract Test { struct Data { uint256 first; uint256 second; } address public someAddress = 0x04068DA6C83AFCFA0e13ba15A6696662335D5B75; mapping(address => Data) public datas; constructor() {} function test(address[] memory users) external view { Data storage data; for (uint256 i = 0; i < users.length; i++) { if (users[i] == someAddress) { data = datas[someAddress]; break; } } } }
這樣的聲明會引起任何問題嗎?
這是一個未初始化的儲存指針,指向插槽 0。我使用的是 0.8.14(版本在這裡很重要)。沒有發出警告。以前的編譯器確實對此提出了警告。
Data storage data
someAddress
位於插槽 0 中,因為它是第一個聲明的儲存變數。所以,如果你寫信給它,契約就會亂塗亂畫someAddress
。是的……非常危險。它為什麼存在?
函式中的儲存指針對於簡潔性和可讀性非常有用。考慮一個中等複雜的結構,其中一個
mapping
or 數組struct
嵌套在另一個mapping
of 中structs
。請記住,此範例非常人為且無用。它只是考慮嵌套結構和一些冗長的語法來解決。你可能會得到類似的東西:
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.14; contract Test { enum GameState {UNDEFINED, PENDING, STARTED, CONCLUDED} struct Player { string name; uint[] games; } struct Game { GameState gameState; Player player1; Player player2; uint8 player1Score; uint8 player2Score; } mapping(address => Player) players; // simplist game ID by row number Game[] games; // fish a game out of the player history function getPlayerGameAtIndex(address player, uint gameIndex) public view returns (Game memory game) { // this expression gets you there return games[players[player].games[gameIndex]]; } // what if you want to write to it? function changePlayer(address player, uint gameIndex, address newPlayer) public { // this is safe because g is initialized to point at a specific instance (slot) Games storage g = games[players[player].games[gameIndex]]; if(g.player1 = msg.sender) g.player1 = newPlayer; if(g.player2 = msg.sender) g.player2 = newPlayer; /* using g (storage pointer) is easier to understand and more gas-efficient than: if(games[players[player].games[gameIndex]].player1 = msg.sender) games[players[player].games[gameIndex]].player1 = newPlayer; if(games[players[player].games[gameIndex]].player2 = msg.sender) games[players[player].games[gameIndex]].player2 = newPlayer; */ } }
這裡有一個關於儲存指針的小解釋。我經常將它們用於那些說他不喜歡它們的人。我擔心的是,誤用可能是災難性的,而且對於剛接觸該語言的人來說,正確使用並不明顯。
https://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089
希望能幫助到你。