Solidity: Können Sie dynamische Arrays in einer Funktion zurückgeben?

Ich weiß, dass ich dynamische Byte-Arrays in Solidity zurückgeben kann, wie im folgenden Code:

function createMemoryArray(uint size) returns (bytes) {
    // Dynamic memory arrays are created using `new`:
    uint[2][] memory arrayOfPairs = new uint[2][](size);
    // Create a dynamic byte array:
    bytes memory b = new bytes(200);
    for (uint i = 0; i < b.length; i++)
        b[i] = byte(i);
    return b;
}

Aber gibt es eine Möglichkeit, so etwas wie ein dynamisches Array von Zeichenfolgen zurückzugeben? Ich habe das Gefühl, dass dies nur ein Implementierungsdetail in Solidity ist, aber es wäre großartig, wenn es einfach alles schön für mich serialisieren würde.

Antworten (4)

Ist es möglich, ein Array von Strings ( string[] ) von einer Solidity-Funktion zurückzugeben?

Noch nicht, da dies zwei Ebenen dynamischer Arrays erfordert (String ist selbst ein dynamisches Array). Dok

Sie können jedoch ein Array of Bytes32 (feste Größe von 32 Byte) zurückgeben. Sie können also versuchen, so etwas zu tun (Sie können Remix kopieren und einfügen , um es zu testen) .

pragma solidity ^0.4.11;
contract ArrayOfBytes32 {
    address creator;
    bytes32[10] bytesArray; // size must be fixed
  
    function ArrayRR() 
    {
        creator = msg.sender;
        uint8 x = 0;
        while(x < bytesArray.length)
        {
            bytesArray[x] = "myString"; 
            x++;
        }
    }
   
    function getArray() constant returns (bytes32[10])
    {
        return bytesArray;
    }
    
    function getValue(uint8 x) constant returns (bytes32)
    {
        return bytesArray[x];
    }
}

Beachten Sie, dass Sie web3.toAcsii() doc verwenden müssen , um das Ergebnis zu konvertieren, wenn Sie web3 verwenden, um mit Ihrem Vertrag zu interagieren

Huh, ich wäre nie auf die Idee gekommen, die häufig gestellten Fragen zum Dokument zu überprüfen. Schöner Fund und interessante Lösung!
Warum kann ich kein dynamisches Array von bytes32 ( bytes32[]) zurückgeben?
Sie können ein dynamisches Array von bytes32 ( bytes32[]) zurückgeben. Was Sie nicht können, ist ein Objekt zurückzugeben, das zwei Ebenen dynamischer Arrays kombiniert.
@RobertZaremba Aber ist bytes32 nicht selbst ein Array? Dann ist Byte 32[] ein zweidimensionales Array
@Andrey Das Problem besteht in zwei Ebenen dynamischer Arrays, nicht in zweidimensionalen Arrays. Sie könnten die Funktion problemlos ein zweidimensionales Array mit jeweils 10 Uints zurückgeben lassen - aber Sie können kein zweidimensionales Array haben, bei dem beide Arrays dynamisch sind. Geben Sie "bytes32" ein, geben Sie nur an, dass 32 Bytes im Speicher zugewiesen werden, es handelt sich also nicht um eine dynamische Variable. Sie wissen immer, dass 32 Bytes Speicher benötigt werden, daher ist es eine statische Variable (kann die Größe während der Laufzeit nicht ändern). Deswegen funktioniert es :)
jetzt kehrt es nur 0x00000000.... ,0x0000000....., ....in Solidität zurück. Außerdem müssen wir in der neueren Version memorySchlüsselwörter im Rückgabetyp hinzufügen, was meiner Meinung nach das Problem für mich verursacht.

Es ist ein altes Problem ... Aber für Neulinge und der Vollständigkeit halber gibt es in Solidity keine Probleme, dynamische Arrays von Paaren oder dynamische Arrays von Strings zurückzugeben, wenn man den modernen Compiler (getestet mit 0.5.6) und das experimentelle ABI-Pragma verwendet :

    pragma experimental ABIEncoderV2;

    ...

    function createMemoryArray(uint size) public pure returns (uint[2][] memory) {
        uint[2][] memory b = new uint[2][](size);
        for (uint i=0; i < b.length; i++) {
            b[i][0] = i;
            b[i][1] = i * 2;
        }
        return b;
    }

    function createStringArray(uint size) public pure returns (string[] memory) {
        string[] memory b = new string[](size);
        for (uint i=0; i < b.length; i++) {
            b[i] = "test";
        }
        return b;
    }
Danke, das sollte die akzeptierte Antwort sein

Gibt dynamische Arrays der Struktur in einer Funktion zurück

pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;
contract Money {
  struct People{
    uint id;
    string name;
    uint amount;
  }
  mapping (uint => People) public peoples;
  event votedEvent(uint indexed _candidateId);
  uint public candidateConut;

  constructor() public {
    candidateConut = 0;
    addCandidate("Holder 1");
    addCandidate("Holder 2");
  }
  function addCandidate(string memory _name) public {
    peoples[candidateConut] = People(candidateConut,_name,0);
    candidateConut++;
  }
  //return Single structure
  function get(uint _candidateId) public view returns(People memory) {
    return peoples[_candidateId];
  }
  //return Array of structure Value
  function getPeople() public view returns (uint[] memory, string[] memory,uint[] memory){
      uint[]    memory id = new uint[](candidateConut);
      string[]  memory name = new string[](candidateConut);
      uint[]    memory amount = new uint[](candidateConut);
      for (uint i = 0; i < candidateConut; i++) {
          People storage people = peoples[i];
          id[i] = people.id;
          name[i] = people.name;
          amount[i] = people.amount;
      }

      return (id, name,amount);

  }
  //return Array of structure
  function getPeoples() public view returns (People[] memory){
      People[]    memory id = new People[](candidateConut);
      for (uint i = 0; i < candidateConut; i++) {
          People storage people = peoples[i];
          id[i] = people;
      }
      return id;
  }
}
Ich ermutige Sie nicht, dies im Hauptnetz zu verwenden, da es experimentell ist und ein kürzlich erschienener Artikel einen Fehler darin gezeigt hat.

Ist es möglich, ein dynamisches Array von Zeichenfolgen ( string[] ) von einer Solidity-Funktion zurückzugeben?

Ja, Sie können es in Bytes serialisieren und wieder in string[] deserialisieren.

In Ihrem Smart Contract:

function toBytes(string[] strArray)
private
pure
returns(bytes serialized) {
    uint startindex = 0;
    uint endindex = strArray.length - 1;

    require(endindex >= startindex);

    if (endindex > (strArray.length - 1)) {
        endindex = strArray.length - 1;
    }

    //64 byte is needed for safe storage of a single string.
    //((endindex - startindex) + 1) is the number of strings we want to pull out.
    uint offset = 64 * ((endindex - startindex) + 1);

    bytes memory buffer = new bytes(offset);
    string memory out1 = new string(32);


    for (uint i = startindex; i <= endindex; i++) {
        out1 = strArray[i];

        stringToBytes(offset, bytes(out1), buffer);
        offset -= sizeOfString(out1);
    }

    return (buffer);
}

function stringToBytes(uint _offst, bytes memory _input, bytes memory _output)
private
pure {
    uint256 stack_size = _input.length / 32;
    if (_input.length % 32 > 0) stack_size++;

    assembly {
        stack_size: = add(stack_size, 1) //adding because of 32 first bytes memory as the length
        for {
            let index: = 0
        }
        lt(index, stack_size) {
            index: = add(index, 1)
        } {
            mstore(add(_output, _offst), mload(add(_input, mul(index, 32))))
            _offst: = sub(_offst, 32)
        }
    }
}


function sizeOfString(string memory _in)
private
pure
returns(uint _size) {
    _size = bytes(_in).length / 32;
    if (bytes(_in).length % 32 != 0)
        _size++;

    _size++; // first 32 bytes is reserved for the size of the string
    _size *= 32;
}

}

Verwenden Sie dann die folgende Funktion, um es zurück zu string[] (mit js) zu deserialisieren:

function hexBytesToStr(hex) {
    let str = '';
    for (let i = 0; i < hex.length; i += 2) {
        let v = parseInt(hex.substr(i, 2), 16);
        if (v) str += String.fromCharCode(v);
    }

    let params = [];
    let res = "";
    for (let i = 0; i <= str.length; i++) {
        if (str.charCodeAt(i) > 31) {
            res = res + str[i];
        }
        else {
            params.push(res);
            res = "";
        }
    }
    params.pop();

    return params;
}