Contract-Development
我應該如何從映射中獲取值?
我和我的朋友正在做一個硬體任務。我們有一個結構:
struct Record { string id; uint requestTime; uint releaseTime; Direction dir; }
我們還有一個映射:
mapping(address => Record[]) data;
我們基本上將
Record
在與一個地址關聯的映射中擁有多個實例。有沒有辦法Record
從映射中讀取實例?像 getter 函式或獲取特定地址作為參數並返回包含屬於該地址Record[]
的實例的數組的東西?Record
function getRecords(address _addr) public view returns(Record[]) { ... //returns recordsfound, which is a Record[] return recordsfound; }
或者這在 Solidity 中不起作用,我們必須製作其他東西?
第一件事。這種糟糕的形式是因為 0.5.0x 和 0.8.3 之間存在顯著差異。您應該指出實際編譯和工作的範圍,或者更好的是,只需聲明您正在使用的編譯器,如下所示:
pragma solidity 0.8.3;
由於這是使用以前“實驗性 ABI”的元素,因此毫無疑問,如果不修改程式碼,程式碼不會在 0.7.6 或更低版本下編譯。
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.3; contract Nested { struct Record { string id; uint requestTime; uint releaseTime; Direction dir; } struct Direction { bool foo; uint bar; } mapping(address => Record[]) records; function insert(address key, string memory id, uint requestTime, uint releaseTime, bool foo, uint bar) public { Direction memory d = Direction({ foo: foo, bar: bar }); Record memory r = Record({ id: id, requestTime: requestTime, releaseTime: releaseTime, dir: d }); records[key].push(r); } function inspect(address key) public view returns(Record[] memory) { return records[key]; } }
您可能發現不能只添加
public
到映射中。你可能會得到類似的東西:
call to Nested.records errored: Error encoding arguments: Error: invalid BigNumber string (argument="value", value="", code=INVALID_ARGUMENT, version=bignumber/5.0.8)
我發現我的實驗的一些迭代似乎編譯成功,然後在執行時產生了那個錯誤,這有點令人不安。恕我直言,如果編譯器拒絕原始碼會更好,除非可以建構可靠的視圖函式 - 一個很好的提醒,在依賴前沿編譯器功能時要提防隱患。
一種更傳統且可能更有效的方法是呈現幾個固定長度的 ABI 函式,如下所示:
function inspectLength(address key) public view returns(uint) { return records[key].length; } function inspectRecord(address key, uint record) public view returns(Record memory) { return records[key][record]; }
這將互動問題推給了客戶。他們可以檢查單個記錄或將它們全部列舉,並且在之前已經看到其大部分值時無需獲取整個數組。
除了由於契約規模而導致的一些額外部署成本外,還可以考慮同時包含這兩種方法 - 獲取所有並獲取一個。
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.0; contract Nested { struct Record { string id; uint requestTime; uint releaseTime; Direction dir; } struct Direction { bool foo; uint bar; } mapping(address => Record[]) records; function insert(address key, string memory id, uint requestTime, uint releaseTime, bool foo, uint bar) public { Direction memory d = Direction({ foo: foo, bar: bar }); Record memory r = Record({ id: id, requestTime: requestTime, releaseTime: releaseTime, dir: d }); records[key].push(r); } function inspect(address key) public view returns(Record[] memory) { return records[key]; } function inspectLength(address key) public view returns(uint) { return records[key].length; } function inspectRecord(address key, uint record) public view returns(Record memory) { return records[key][record]; } }
希望能幫助到你。