Solidity
將地址儲存在數組或映射中?
我的合約目前為前端提供一系列地址:
address[] public addresses; function getAddresses() public view returns (address[]) { return addresses; }
我擔心可擴展性。可以返回的地址數組的長度是否有任何限制?使用計數器將所有地址儲存在映射中會更好嗎?
mapping public (uint => address) addressMap; uint public addressCounter;
這似乎更具可擴展性,但需要前端對合約進行更多呼叫,然後使用每個地址進行另一次呼叫。
不同類型的索引儲存之間存在權衡,我們中的許多人發現我們需要使用選項的組合來完成所有給定合約的目標。
一次性傳遞整個列表存在可伸縮性問題。當客戶可能已經擁有大部分列表時,沒有必要這樣做。無論如何,當所有操作都安排為固定成本函式時,您會發現實現了規模化。
儘管您的範例很簡單,但我將向您展示如何滿足最常見的長期儲存需求(長期,因為以後通常不會修改契約)。
可迭代列表,如您的範例,但單獨返回它們:
function getAddressCount() public view returns(uint count) { return addesses.length; } function getAddressAtRow(uint row) public view returns(address theAddress) { return addresses[row]; }
您可能(很可能)發現知道(無需迭代)地址是否在某處很方便,
addresses[]
以避免出現兩次附加相同地址等問題。您希望合約擷取錯誤的客戶端請求,因此它需要一種方法來大規模執行此操作(無需迭代)。映射可以提供幫助。除了數組:mapping(address => bool) bool isActuallyAnAddressOnMyList;
這可以容納以下內容:
function isAddress(address check) public view returns(bool isIndeed) { return isActuallyAnAddressOnMyList[check]; }
您可以通過一種模式獲得一些更高級的資訊,該模式將容納有關地址的其他屬性(您需要多少屬性):
struct AddressStruct { bool isAddress; // more fields } mapping(address => AddressStruct) public addressStructs; address[] public addressList;
您可以使合約狀態完全可發現:
function getAddressCount() public constant returns(uint count) { return addressList.length; } function getAddressStruct(address fetch) public view returns(bool isAddress, ... ) { require(isAddress(fetch); return(addressStructs[fetch].isAddress, ...); }
您可以(應該)在更改發生時發出事件:
event LogNewAddress(address sender, address newAddress); function appendAddress(address newAddress) returns(bool success) { require(!isAddress(newAddress)); addressList.push(newAddress); addressStructs[newAddress].isAddress = true; LogNewAddress(msg.sender, newAddress); return true; }
通過發出事件,您為已經同步的客戶端提供了一種在新地址到達時簡單地記錄新地址的方法。這也意味著理論上可以在正確完成時重建合約的整個狀態歷史。
同時使用映射和數組的想法增加了插入氣體成本,但它解決了僅使用一個或另一個的權衡。此處描述了各種結構和權衡:Solidity 是否存在解決良好且簡單的儲存模式?
希望能幫助到你。