Копирование памяти типа struct memory[] в хранилище еще не поддерживается

Как добавить новый пустой экземпляр Parent в список родителей в приведенном ниже примере кода? я продолжаю получать

UnimplementedFeatureError: Copying of type struct Test.Child memory[] memory
to storage not yet supported.

Минимальный пример:

contract Test {
  struct Child { } 
  struct Parent { Child[] children; }

  Parent[] parents;

  function test() {
    parents.push(Parent(new Child[](0)));
  }
}

person Jonas H.    schedule 18.03.2018    source источник


Ответы (2)


Вы не можете делать то, что пытаетесь сделать с динамическими массивами. Вам нужно будет немного изменить свой подход, чтобы заставить его работать.

contract Test {
  struct Child { } 
  struct Parent { 
      mapping(uint => Child) children;
      uint childrenSize;
  }

  Parent[] parents;

  function testWithEmptyChildren() public {
      parents.push(Parent({childrenSize: 0}));
  }

  function testWithChild(uint index) public {
      Parent storage p = parents[index];

      p.children[p.childrenSize] = Child();
      p.childrenSize++;
  }
}

Используйте Parent.childrenSize, если вам нужно повторить Parent.children где-то еще в вашем контракте.

Кроме того, вы можете увеличить размер массива parents и использовать нулевые значения Solidity по умолчанию.

contract Test {
  struct Child { } 
  struct Parent { Child[] children; }

  Parent[] parents;

  function test() public {
      parents.length++;
      Parent storage p = parents[parents.length - 1];

      Child memory c;

      p.children.push(c);
  }
}
person Adam Kipnis    schedule 18.03.2018
comment
Спасибо! Итак, вы говорите, что массивы нельзя использовать таким образом, и вам придется использовать сопоставления в качестве обходного пути? - person Jonas H.; 19.03.2018
comment
Для данного конкретного примера да. Проблема в том, что вы пытаетесь создать то, что по сути является пустым Parent, в котором есть необязательные члены. Это может быть результатом того, что вы предоставили минимальный пример, но подход немного странный, потому что обычно вы не пытаетесь создать пустой Parent, подобный этому. Вы просто увеличите размер массива, и Solidity автоматически установит значения равными нулю. Я отредактирую ответ, чтобы включить этот последний пункт. - person Adam Kipnis; 19.03.2018

Это не работает (по крайней мере, начиная с Solidity 0.4.24), если тип дочернего массива является другой структурой, но работает, если тип дочернего массива является примитивным типом, таким как uint256.

Итак, если у вас есть, например.

struct Child {
  uint256 x;
  bytes32 y;
}

то вы можете определить:

struct Parent {
  uint256[] childXs;
  bytes32[] childYs;
}

и тогда вы могли бы написать:

parents.push(Parent({
    childXs: new uint256[](0),
    childYs: new bytes32[](0)
}));

(Тот же обходной путь применим, когда вы хотите передать массив структур в качестве аргумента общедоступной функции.)

Это не идеально, но работает.

P.S. На самом деле (если вы используете дочерние элементы примитивного массива), вы можете просто написать:

Parent memory p;
parents.push(p);
person dwardu    schedule 06.07.2018