Solidity

如何正確初始化嵌套儲存數組/結構?

  • January 18, 2020
contract Contract {

struct A {
 int a;
}

struct B {
 A[] as;
}

mapping(address => B[]) bs;

function addB(B memory b) {
 bs[msg.sender].push(...???...);
}

}

我嵌套了一堆數組和結構,我不知道如何正確地將一個 B 添加到bs.

嵌套地獄

是的。

這是循環的:

struct B {
 B[] as;
}

B 包含 B 的數組?

結構內部結構的動態數組推動了編譯器可以處理的限制。您必須構造該結構的記憶體實例並使用不存在的 push 方法,然後將作品複製到儲存中。

作為一般建議,不要與之抗爭,而是使用鍵數組並將結構放在可以在結構之外訪問的映射中。

大致:

struct Inner {
 members ...
}

struct Outer {
 address[] InnerKeys;
 more members ... 
}

mapping(address => Inner) innerStructs;
mapping(address => Outer) outerStructs;

酌情使用地址、bytes32 或 uint 作為鍵。

你會發現更容易應對。

你沒有說你需要用這個做什麼。它通常與臨時集有關,例如使用位置、成員資格等,這可能意味著需要在邏輯上刪除和迭代成員。您可能會發現這種方法很有用:https ://github.com/rob-Hitchens/UnorderedKeySet

這個小小的塗鴉在應用程序級別的問題上取得了不錯的進展,而不是陷入組織。

pragma solidity ^0.5.1;

import "./HitchensUnorderedAddressSet.sol";

contract NestedStructs {

   using HitchensUnorderedAddressSetLib for HitchensUnorderedAddressSetLib.Set;

   struct UserStruct {
       uint balance;
       bool active;
       HitchensUnorderedAddressSetLib.Set followingSet;
       HitchensUnorderedAddressSetLib.Set followerSet;
   }

   mapping(address => UserStruct) userStructs;
   HitchensUnorderedAddressSetLib.Set userSet;

   function createUser(address user) public { // access control is set aside for brevity
       UserStruct storage u = userStructs[user];
       userSet.insert(user); // revert on deuplicate keys
       u.active = true;
   }

   function join() public {
       createUser(msg.sender);
   }

   function followUser(address followed ) public {
       require(userSet.exists(msg.sender), "Join first please.");
       require(userSet.exists(followed), "Follow a joined user please.");
       UserStruct storage u = userStructs[msg.sender];
       UserStruct storage f = userStructs[followed];
       u.followingSet.insert(followed);
       f.followerSet.insert(msg.sender); // these revert on duplication
   }

   function unFollowUser(address unfollow) public {
       // You can add requires to create more app/human friendly error messages
       UserStruct storage u = userStructs[msg.sender];
       UserStruct storage f = userStructs[unfollow];
       u.followingSet.remove(unfollow);
       f.followerSet.remove(msg.sender); // these revert if there was no follower join to start with
   }

   function isUser(address user) public view returns(bool) {
       return userSet.exists(user);
   }

   function userCount() public view returns(uint) {
       return userSet.count();
   }

   function userInfo(address user) public view returns(uint balance, bool active, uint followingCount, uint followerCount) {
       UserStruct storage u = userStructs[user];
       balance = u.balance;
       active = u.active;
       followingCount = u.followingSet.count();
       followerCount = u.followerSet.count();
   }

   function userFollowerAtIndex(address user, uint index) public view returns(address) {
       return userStructs[user].followerSet.keyAtIndex(index);
   }

   function userFollowingAtIndex(address user, uint index) public view returns(address) {
       return userStructs[user].followingSet.keyAtIndex(index);
   }
}

這裡還有另一個使用 Set 庫的範例:Efficient Solidity storage pattern for a directional weighted graph

希望能幫助到你。

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