web-dev-qa-db-ja.com

ソリディティアレイのポップ機能はありますか?

Solidityを使用してデータを配列にプッシュしました。ポップにも同様の機能はありますか?

string[] myArray;
myArray.Push("hello")

これに対する最善の解決策は何ですか? Solidityで動的配列の要素を削除するにはどうすればよいですか?

5
Suraj Kohli

更新2-19-2019:Joelが以下で指摘したように、popが組み込み配列サポートに追加されました。 https://solidity.readthedocs.io/en/v0.5.4/types.html#array-members を参照してください。他の人が古いバージョンのSolidityを使用している場合に備えて、元の回答をここに残します。


Solidityにはポップ機能はありません。アレイを維持するために検討できるいくつかのオプションがあります。

ギャップを削除して残す

最も簡単な解決策は、特定のインデックスの要素をdeleteすることです。

_string element = myArray[index];
delete myArray[index];
return element;
_

ただし、これによって配列内の要素がシフトされることはなく、配列内に「文字列0」の要素が残ります。この要素を確認するには、次を使用します

if(bytes(myArray[index]).length > 0) ...

スワップと削除

配列内の順序を気にしない場合は、要素を配列内の最後の要素と交換してから、以下を削除できます。

_string element = myArray[index];
myArray[index] = myArray[myArray.length - 1];
delete myArray[myArray.length - 1];
myArray.length--;
return element;
_

Shiftを使用して削除

配列の順序が重要な場合は、要素を削除してから、残りのすべての要素を左にシフトできます。

_string element = myArray[index];
for (uint i = index; i < myArray.length - 1; i++) {
  myArray[index] = myArray[index + 1];
}
delete myArray[myArray.length - 1];
myArray.length--;
return element;
_

これはオプションの中で最も高価になることに注意してください。アレイが非常に長い場合は、ガスの使用量が多くなります。

@Jedsadaの提案に関連して、ライブラリとしてのバージョンを次に示します。

_pragma solidity ^0.4.24;

library StackLib {
  using StackLib for Stack;

  struct Stack {
    uint[] _items;
  }

  function pushElement(Stack storage self, uint element) internal returns (bool) {
    self._items.Push(element);
  }

  function popElement(Stack storage self) internal returns (uint) {
    uint element = self.peek();

    if (self.size() > 0)
      delete self._items[self.size() - 1];

    return element;
  }

  function peek(Stack storage self) internal returns (uint) {
    uint value;

    if (self.size() > 0)
      value = self._items[self.size() - 1];

    return value;
  }

  function size(Stack storage self) internal returns (uint8) {
    return self.size();
  }
}
_

使用例(重要な注意:popElementを使用して値をクライアントに返すことはできません。このメソッドは状態を変更するため、トランザクション内でのみ使用する必要があります。):

_contract Test {
  using StackLib for StackLib.Stack;

  StackLib.Stack numbers;

  function add(uint v) public {
    numbers.pushElement(v);
  }

  function doSomething() public {
    for (uint8 i = 0; i < numbers.size(); i++) {
      uint curNum = numbers.popElement();

      // do something with curNum
    }
  }
}
_

追記:残念ながら、varは0.4.20以降非推奨になり、ジェネリックに代わるものはありません。特定のタイプに合わせてカスタマイズする必要があります。

6
Adam Kipnis

試すことができます...

pragma solidity ^0.4.17;

contract TestArray {
   uint[] public items;

   constructor () public {
      items.Push(1);
      items.Push(2);
      items.Push(3);
      items.Push(4);
   }

   function pushElement(uint value) public {
      items.Push(value);
   }

   function popElement() public returns (uint []){
      delete items[items.length-1];
      items.length--;
      return items;
   }

   function getArrayLength() public view returns (uint) {
      return items.length;
   }

   function getFirstElement() public view returns (uint) {
      return items[0];
   }

   function getAllElement()  public view returns (uint[]) {
      return items;
   }
}

はい、v0.5.0の時点であります( 詳細はこちら ):

動的ストレージ配列とバイト(文字列ではない)には、配列の末尾から要素を削除するために使用できるpopというメンバー関数があります。これは、削除された要素に対して暗黙的に:ref:deleteも呼び出します。

1