Как инициализировать пустой массив внутри структуры?

Есть ли ошибка в том, как я инициализирую Bar b в функции foobar?

contract Foo {

    struct Bar {
        address owner;
        uint[] x;
    }

    Bar[] public bars;

    function foobar(address a) public {
        Bar storage b = Bar(a, new uint[]) // will that be an array in storage?
        bars.push(b)
    }

}

Ответы (3)

В Solidity нет необходимости инициализировать storageмассивы. Только memoryмассивы должны быть инициализированы перед использованием.

Так что в вашем случае нет необходимости инициализировать xвнутри Bar, если вы не присваиваете значение одному из xиндексов внутри вашего foobar. На самом деле, выполнение инициализации в вашем коде будет потреблять газ без всякой причины.

Следующий код хорошо подходит для вашего случая:

function foobar(address a) public {
    Bar memory b;
    b.owner = a;
    //When 'b' is pushed to 'bars' array:
    // (1) 'b' will be converted from memory to storage.
    // (2) And 'x' inside it will be initialized automatically.
    bars.push(b); 
}

Однако, если вам нужно получить доступ к x и ввести какое-то значение, вы можете использовать push:

function foobar2(address a, uint x0) public {
    Bar memory b;
    b.owner = a;
    bars.push(b);
    //Trying: b.x[0] = x0; will generate error. Since, b.x is a memory array that is not initialized!
    bars[bars.length - 1].x.push(x0); //This will work fine!
}

На самом деле вы все еще можете инициализировать свой массив памяти как пустой, как показано ниже:

function foobar3(address a) public {
    Bar memory b = Bar(a, new uint[](0)); //Thanks to "James Duffy" for his answer.
    bars.push(b);
}

Последнее, что нужно упомянуть, это то, что: если у вас есть несколько значений, которые вам нужно вставить в свой xмассив, вы можете сделать это следующим образом:

function foobar4(address a, uint[] _x) public {
    Bar memory b = Bar(a, _x);
    bars.push(b);
}

Или как следует. Но это будет потреблять больше газа:

function foobar5(address a, uint[] _x) public {
    Bar memory b;
    b.owner = a;
    bars.push(b);

    Bar storage c = bars[bars.length - 1]; // Get the newly added instance of the storage struct
    for (uint i = 0; i < _x.length; i++) {
        c.x.push(_x[i]);
  }

Проверьте полный код на хорошем EthFiddler: https://ethfiddle.com/fQI6Khgz3E

Добро пожаловать. И спасибо Георгиосу Константинопулосу и Loom Network: medium.com/loom-network/…
После вызова foobar, foobar2 или foobar3 я получаю значение bars[0] == {owner: address } вообще без свойства x!!! Это полностью игнорируется. Как это возможно? Что я делаю неправильно?
Я понял, почему это происходит. Необходимо иметь отдельный геттер для получения массивов из таких структур, как getXFromBar.

Рабочая скрипка:

https://ethfiddle.com/Yn6fLiAjto

Один из способов выполнить эту работу — создать временный объект Barв памяти перед его отправкой bars( Bar memory bвместо Bar storage b). Затем Solidity автоматически скопирует данные структуры из памяти в хранилище. См. https://ethereum.stackexchange.com/a/4476/22415 для более подробной информации.

Также new uint[]есть функция, которая требует аргумента размера, например new uint[](8).

Таким образом, полностью эта строка должна читатьсяBar memory b = Bar(a, new uint[](8));

Я понимаю! Итак, я не могу назначить массив динамического размера структуре при ее инициализации?
есть еще ответы?

Попробуй это:

struct Address {
    address[] addressList;
}

function createProposal() public {
    address[] memory emptyAddressList;
    Address memory _address = Address({
       addressList: emptyAddressList
    })
}