【问题标题】:Soldity: Iterate through address mappingSolidity:遍历地址映射
【发布时间】:2018-07-31 14:06:58
【问题描述】:

我正在寻找一种方法来遍历 Solidity 中的映射。例如我有这个映射:

mapping (address => uint) private shares;

我想在一个函数中遍历所有地址,并根据它们的份额向它们发送以太币。

类似:

function giveOutEth() onlyOwner returns (bool success){
for(uint i=0; i < shares.length ; i++){
//get the address and send a value
}

}

我怎样才能做到这一点?

谢谢

【问题讨论】:

    标签: blockchain ethereum solidity smartcontracts ether


    【解决方案1】:

    如果您想要更通用的东西,可以使用库。我在下面包含了我正在使用的一个。它可能会使用一些改进(即,Element 应该更改为接口)并且可能有点矫枉过正(另外,TBH 我还没有进行任何气体消耗比较)。来自更面向对象的背景,我更喜欢使用这样的可重用库,但鉴于 Solidity 的限制,这是我能想到的最好的方法。

    随意使用和/或改进它。

    pragma solidity ^0.4.19;
    pragma experimental "ABIEncoderV2";
    // experimental encoder needed due to https://github.com/ethereum/solidity/issues/3069
    
    library SetLib {
      using SetLib for Set;
    
      struct Set {
        mapping(address => IndexData) _dataMap;
        uint16 _size;
        IndexData[] _dataIndex;
      }
    
      struct IndexData {
        uint16 _index;
        bool _isDeleted;
        Element _element;
      }
    
      struct Element {
        address _value;
        uint8 _status;
      }
    
      function add(Set storage self, Element element) internal returns (bool) {
        if (element._value == 0x0 || self.contains(element)) {
          return false;
        }
    
        IndexData memory data;
    
        data._index = uint16(self._dataIndex.length);
        data._element = element;
    
        self._dataMap[element._value] = data;
        self._dataIndex.push(data);
        self._size++;
    
        return true;
      }
    
      function update(Set storage self, Element element) internal {
        if (element._value != 0x0) {
          IndexData storage data = self._dataMap[element._value];
    
          if (data._element._value == element._value && !data._isDeleted && element._status != data._element._status)
            data._element._status = element._status;
        }
      }
    
      function getByIndex(Set storage self, uint16 index) internal constant returns (Element) {
        IndexData storage data = self._dataIndex[index];
    
        if (!data._isDeleted) {
          return data._element;
        }
      }
    
      function get(Set storage self, address addr) internal constant returns (Element) {
        IndexData storage data = self._dataMap[addr];
    
        if (!data._isDeleted) {
          return data._element;
        }
      }
    
      function contains(Set storage self, Element element) internal constant returns (bool) {
        return self.contains(element._value);
      }
    
      function contains(Set storage self, address addr) internal constant returns (bool) {
        if (addr != 0x0) {
          IndexData storage data = self._dataMap[addr];
    
          return data._index > 0 && !data._isDeleted;
        }
    
        return false;
      }
    
      function remove(Set storage self, uint16 index) internal returns (Element) {
        IndexData storage data = self._dataIndex[index];
    
        if (data._element._value != 0x0 && !data._isDeleted) {
          data._isDeleted = true;
          self._size--;
          return data._element;
        }
      }
    
      function remove(Set storage self, address addr) internal returns (Element) {
        if (addr != 0x0) {
          IndexData storage data = self._dataMap[addr];
    
          if (data._element._value != 0x0 && !data._isDeleted) {
            data._isDeleted = true;
            self._size--;
            return data._element;
          }
        }
      }
    
      function size(Set storage self) internal constant returns (uint16) {
        return self._size;
      }
    }
    
    library IteratorLib {
      using SetLib for SetLib.Set;
    
      struct Iterator {
        bool _started; // using bool instead of making _curIndex int32 for initial state.
        uint16 _curIndex;
        uint16 _size;
      }
    
      function iterator(SetLib.Set storage set) internal constant returns (IteratorLib.Iterator) {
        return IteratorLib.Iterator(false, 0, set.size());
      }
    
      function hasNext(Iterator self, SetLib.Set storage set) internal constant returns (bool) {
        uint16 testIndex = self._curIndex;
    
        while (testIndex < self._size) {
          if (set._dataIndex[testIndex]._element._value != 0x0 && !set._dataIndex[testIndex]._isDeleted)
            return true;
    
          testIndex++;
        }
    
        return false;
      }
    
      function next(Iterator self, SetLib.Set storage set) internal constant returns (SetLib.Element) {
        SetLib.Element memory element;
    
        do {
          if (self._started) {
            self._curIndex++;
          }
          else {
            self._started = true;
          }
    
          element = set.getByIndex(self._curIndex);
        }
        while (element._value != 0x0 && self._curIndex < self._size);
    
        return element;
      }
    }
    

    【讨论】:

      【解决方案2】:

      我收到了 drlecks 的回复:

      contract  Holders{
      
      uint _totalHolders; // you should initialize this to 0 in the constructor
      mapping (uint=> address ) private holders;
      mapping (address => uint) private shares;
      
      function GetShares(uint shares) public {
          ... 
          holders[_totalHolders] = msg.sender;
          shares[msg.sender] = shares; 
          _totalHolders++;
          ...
      } 
      
      function PayOut() public {
          ...
          uint shares;
          for(uint i = 0 ; i<_totalHolders; i++) {
              shares = shares[holders[i]];
              ...
          }
          ... 
      } 
      

      }

      但请记住,它会消耗 gas,也许利益相关者提取他们的 ETH 并自己支付 gas 费用会更好。

      【讨论】:

        猜你喜欢
        • 2019-02-26
        • 2012-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        相关资源
        最近更新 更多