Solidity

為什麼 Solidity Compiler 允許在函式內聲明儲存變數?

  • June 22, 2022

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。是的……非常危險。

它為什麼存在?

函式中的儲存指針對於簡潔性和可讀性非常有用。考慮一個中等複雜的結構,其中一個mappingor 數組struct嵌套在另一個mappingof 中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

希望能幫助到你。

引用自:https://ethereum.stackexchange.com/questions/130563