web-dev-qa-db-fra.com

Existe-t-il une fonctionnalité pop pour les tableaux de solidité?

J'ai utilisé solidity pour pousser des données dans un tableau. Existe-t-il une fonction similaire pour la pop?

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

Quelle est la meilleure solution pour cela? Comment puis-je supprimer un élément dans un tableau dynamique en toute solidité?

5
Suraj Kohli

Mise à jour 2-19-2019 : Comme Joel l'a souligné ci-dessous, pop a été ajouté au support de tableau intégré. Voir https://solidity.readthedocs.io/en/v0.5.4/types.html#array-members . Laisser la réponse originale ici au cas où d'autres utiliseraient d'anciennes versions de Solidity.


Il n'y a pas de fonction pop dans Solidity. Vous avez quelques options que vous pouvez envisager pour maintenir votre tableau.

Supprimer & Laisser les lacunes

La solution la plus simple consiste à juste delete l'élément à un index spécifique:

string element = myArray[index];
delete myArray[index];
return element;

Cependant, cela NE DÉCALERA PAS les éléments de votre tableau et laissera un élément "chaîne 0" dans votre tableau. Pour vérifier cet élément, vous utiliseriez

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

Swap & Delete

Si vous ne vous souciez pas de l'ordre dans votre tableau, vous pouvez échanger l'élément avec le dernier élément de votre tableau, puis supprimer:

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

Supprimer avec Shift

Si l'ordre dans votre tableau est important, vous pouvez supprimer l'élément, puis décaler tous les éléments restants vers la gauche.

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;

Notez que ce sera l'option la plus chère. Si votre réseau est très long, votre consommation de gaz sera élevée.

En corrélation avec la suggestion de @ Jedsada, voici une version en tant que bibliothèque:

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();
  }
}

Exemple d'utilisation (Remarque importante: vous ne pouvez pas utiliser popElement et renvoyer la valeur à un client. Cette méthode change d'état et ne doit être utilisée que dans une transaction.):

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
    }
  }
}

Note complémentaire: Malheureusement, var est obsolète depuis le 0.4.20 et les génériques ne peuvent pas être remplacés. Vous devez personnaliser pour un type spécifique.

6
Adam Kipnis

Tu peux essayer...

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;
   }
}
1

Oui, à partir de la version 0.5.0 ( détails ici ):

Les tableaux de stockage dynamique et les octets (pas de chaîne) ont une fonction membre appelée pop que vous pouvez utiliser pour supprimer un élément de la fin du tableau. Cela appelle aussi implicitement: ref: delete sur l'élément supprimé.

0
Joel Oduro-Afriyie