Solidity

如何在映射中持久分配對結構的分配?

  • March 6, 2022

以下是我面臨的問題的簡化;

pragma solidity 0.4.18;

contract ValueSetter {
 struct BasicValue {
   uint256 value;
 }

 address my_address; // Just for the require later
 BasicValue fixed_value;
 mapping(address => BasicValue) fixed_values;

 function ValueSetter(address init_address) public {
   my_address = init_address;
   fixed_values[init_address] = fixed_value;
 }

 function set_value(uint256 my_value) external {
   // Just to prove that the bug isn't in my calling params
   require(msg.sender == my_address && my_value != 0);

   fixed_values[msg.sender].value = my_value;

   assert(fixed_value.value != 0);
 }
}

當我set_value用非零值呼叫時,我點擊了斷言。看起來問題是在這一行中,

fixed_values[msg.sender].value = my_value;

我嘗試分配給映射內的結構並沒有分配給儲存在fixed_value. 我也嘗試了以下方法;

BasicValue storage basic_val = fixed_values[msg.sender];
basic_val.value = my_value;

但這不會改變結果。我在solidity文件中讀到,

儲存和記憶體之間以及狀態變數(甚至來自其他狀態變數)之間的分配總是創建一個獨立的副本

如果是這種情況,那麼我怎樣才能讓結構“脫離”映射,以便在本地使用它?

(注意;上面的合約看起來比它需要的複雜得多,因為真正的合約有更多的要求。例如,結構中有多個屬性,初始化時聲明的結構不止一個,還有超過映射中的一個結構,我需要執行涉及多個其中一個的邏輯。)

這些行是不必要的

BasicValue fixed_value;
fixed_values[my_address] = fixed_value;

但真正的問題是這條線

assert(fixed_values[msg.sender].value != 0);

因為您想要該索引處的結構。

pragma solidity 0.4.18;

contract ValueSetter {

 struct ValueStruct {
   uint256 value;
 }

 address public my_address; // Just for the require later

 mapping(address => ValueStruct) public valueStructs;

 function ValueSetter() public {
   my_address = msg.sender;
 }

 function set_value(uint256 my_value) external {

   // this shows the function is called by the deployer account
   require(msg.sender == my_address && my_value != 0);

   // this stores a uint in the .value element of the ValueStruct 
   // stored in the mapping at the index which is the sender

   valueStructs[msg.sender].value = my_value;

   // this just gets confirms the value is where we put it
   assert(valueStructs[msg.sender].value != 0);
 }
}

希望能幫助到你。

是的,所有狀態變數都在婚前儲存在區塊鏈中。但是來到你的 qus 為什麼:

function ValueSetter(address init_address) public {
   my_address = init_address;
   fixed_values[init_address] = fixed_value;
}

在上面的程式碼中,您的初始化 fixed_values[init_address] = fixed_value;意味著在內部fixed_value = BasicValue(0),這將被分配給fixed_values[init_address] = fixed_value;

在內部,您的程式碼如下所示:

function ValueSetter(address init_address) public {
   fixed_value = BasicValue(0);
   my_address = init_address;
   fixed_values[init_address] = fixed_value;
}

來到你那裡有一個邏輯錯誤:

 function set_value(uint256 my_value) external {
   // Just to prove that the bug isn't in my calling params
   require(msg.sender == my_address && my_value != 0);

   fixed_values[msg.sender].value = my_value;

   assert(fixed_value.value != 0);
 }

根據我的解釋,fixed_value.value 為零。斷言將失敗。您的交易將恢復到以前的狀態。它不會將目前值保存到區塊鏈。但交易將作為失敗記錄到鏈上。

於是修改程式碼:pragma solidity 0.4.18;

contract ValueSetter {
 struct BasicValue {
   uint256 value;
 }

 address my_address; // Just for the require later
 BasicValue fixed_value;
 mapping(address => BasicValue) fixed_values;

 function ValueSetter(address init_address) public {
   my_address = init_address;
   fixed_values[init_address] = BasicValue(1000);
 }

 function set_value(uint256 my_value) external {
   // Just to prove that the bug isn't in my calling params
   require(msg.sender == my_address && my_value != 0);

   fixed_values[msg.sender].value = my_value;

   //assert(fixed_value.value != 0);
 }
}

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