每個地址的項目列表
我正在開發一個 dApp,我正在嘗試解決以下問題。我想將地址映射到我的一份契約中的動態項目列表。這樣,當使用者登錄時,他/她就有了自己的項目列表(有點像 cryptokittens 的工作方式,對於每個地址,您都可以擁有該地址的小貓列表)。我的問題是:我可以做這個映射嗎?是不是很糟糕/沒有效率?有人告訴我,我真的不知道如何有效地做到這一點。與我一起工作的一些人建議將此資訊放在鏈下。這是正確的方法嗎?我寧願一切都在鏈上。
謝謝
這在某種程度上效率不高,您必須呼叫使用者擁有的每個項目,因為目前您無法以可靠的方式返回結構列表。但是您可以輕鬆地返回屬於使用者的項目的 id 列表,然後獲取有關這些項目的資訊(不幸的是,也是一項一項)。但是由於這個返回項目資訊的函式是“查看”函式,所以它們不會花費任何氣體。如果使用者沒有數十或數百個項目,我認為這不是問題。
下面的程式碼只是一個例子,它缺乏安全邏輯(任何人都可以呼叫任何函式)
pragma solidity ^0.4.21; contract ItemsAndUsers { struct Item { uint id; string nameOfItem; string typeofItem; uint value; } //In this form user struct doesn't make much sense as it has only one field, //but we can imagine it being more complex struct User { address userAddress; } Item[] public allItems; User[] public allUsers; mapping (address => uint[]) public userItemsIds; mapping (uint => address) public itemIdToUser; function createUser() public { uint[] memory items; User memory user = User({ userAddress: msg.sender }); allUsers.push(user); } function createItem(string _name, string _type, uint _value) public { Item memory item = Item({ id: allItems.length, nameOfItem: _name, typeofItem: _type, value: _value }); allItems.push(item); } function assignItemToUser(address _userAddress, uint _itemId) public { itemIdToUser[_itemId] = _userAddress; userItemsIds[_userAddress].push(_itemId); } //This function will return list of ids of all items belonging to the _userAddress function getUserItems(address _userAddress) public view returns (uint[] items){ return userItemsIds[_userAddress]; } //This function returns all information about single item function getItemInfo(uint _itemId) public view returns (uint id, string nameOfItem, string typeofItem, uint value) { Item memory item = allItems[_itemId]; return (item.id, item.nameOfItem, item.typeofItem, item.value); } }
所以基本上你必須呼叫一次 getUserItems 函式,並為這個使用者擁有的每個項目呼叫 getItemInfo
您想要一個帶有索引的映射結構,並且您想要儲存在一個帶有索引的映射結構中。
映射,因此您可以一舉解決
keyExists(key)
或解決。getDetails(key)
索引,因此您可以計算鍵並列舉列表。每次插入映射結構時,您還應該向索引附加一個鍵,注意避免重複鍵。
struct MemberStruct { bool isMember; // ... carry on } mapping(address => MemberStruct) public memberStructs; address[] public memberList;
這是一個涵蓋大多數基礎的基本結構。如果您不需要刪除,生活會更輕鬆。在這裡查看更好的範例:Solidity 是否有解決良好且簡單的儲存模式?
您可以使用該模式在單個契約中維護兩個列表。您所描述的是一對多連接。您可能需要兩個表的 CRUD 操作,以及一種強制引用完整性的方法。
為此,您必須管理兩個表中的雙向指針。https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart-contracts-a9ab1427ff42
正如邁克非常正確地指出的那樣。維護內部組織非常重要,這樣您就可以在沒有無限
for
循環或遞歸的情況下完成所有操作。如果您發現自己在循環瀏覽記錄,則表明事情偏離了軌道。例如,您必須安排事情以便立即知道所需的行。希望能幫助到你。