30

I'd like to return struct type User. However, when I tried the following getUser function, it returns an error. Is there any way that struct data would be returned from a function?

Contract

struct User{
    uint256 user_id;
    bytes32 name;
    bytes32 address;
    bytes32 birth_day;
}
mapping (uint256 => User) public users;

function getUser(uint256 user_id) constant returns (User) {
        return users[user_id];
}

Error

client/lib/contracts/User.sol: Solidity errors: :125:58: Error: Expected type name
function getUser(uint256 user_id) constant returns (struct User) {

9 Answers 9

43

You can not return a struct because Solidity implements them only as a loose bag of variables, they are not real objects.

You can use a solution from this answer: https://ethereum.stackexchange.com/a/3614/264

Update

Since 0.4.17 you can use pragma experimental ABIEncoderV2 to return structs. Of course, until the experimental keyword is removed, it's not safe to use it in production apps.

4
  • 5
    The answer is a year old. Are there any updates? Or we still can not return struct array from solidity function. Jul 29, 2017 at 9:38
  • 1
    @PrashantPrabhakarSingh I updated the answer. Nov 22, 2018 at 11:21
  • 1
    @PaulBerg again one year from now ;) any update?
    – Senju
    Jun 13, 2019 at 19:13
  • 1
    @Senju It's safe to use it in Production, it's been 3 years after all Jul 6, 2019 at 15:36
5

Passing structs is available in 0.4.17 with pragma experimental ABIEncoderV2. See https://github.com/ethereum/solidity/issues/40

4

This will only work when the struct is passed around within the contract via the use of internal function calls. Even using ABIEncoderV2, when attempting to return a struct via a public or external function will give the following error: error: Failed to decode output: Error: Unsupported or invalid type: tuple

1

This does not work straight forward but here is the workaround. https://medium.com/coinmonks/solidity-tutorial-returning-structs-from-public-functions-e78e48efb378

1
struct User{
    uint256 user_id;
    bytes32 name;
    bytes32 address;
    bytes32 birth_day;
}
mapping (uint256 => User) public users;

function getUser(uint256 user_id) constant returns (uint) {
return users[user_id].user_id;

}
1

Solidity automatically adds a getter to public mappings and returns a tuple, so there is no need for a function like getUser(uint256 user_id).

Check out solidity documentation for returning multiple values

0

A solution I discovered to return the array as a string,

struct User{
   uint256 user_id;
   bytes32 name;
   bytes32 address;
   bytes32 birth_day;
}
mapping (uint256 => User) public users;

now create a function,

function getUsers() public view returns(string memory) {
    string memory output="";
    for (uint i = 0; i < users.length; i++) {
        output = string(abi.encodedPack(output,"[", users[i].user_id, ",", users[i].name, ",", users[i].address, ",", users[i].birth_day, "]"));
    }
    return output;
}
1
  • 1
    be careful with the type error ! abi.encodePack ==> abi.encodePacked Mar 11 at 16:36
0
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

pragma experimental ABIEncoderV2;

contract UserMgnt{
   struct User{
        uint256 user_id;
        bytes32 name;
        bytes32 address;
        bytes32 birth_day;
    }
    mapping (uint256 => User) public users;
    
    function getUser(uint256 user_id) constant returns (User memory) {
            return users[user_id];
    }
}

This worked for me. I had to add pragma experimental ABIEncoderV2; in the top of my solidity file and I had to make sure to add the keyword memory to returned type User function getUser(uint256 user_id) constant returns (User memory) {...}.

I hope this helps someone out there.

0

[UPDATE] Solidity Compiler version >= 0.8.0

If you want to retrieve a specific struct (in this case User's struct) from a mapping, you can do it without ABIEncoderV2. You can see this smart contract code, after this line, to do this operation:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract RetrieveStruct {

    struct User{
        uint256 _user_id;
        bytes32 _name;
        bytes32 _address;
        bytes32 _birth_day;
    }
    mapping (uint256 => User) public users;

    function setUser(uint _idUser) public {
        users[_idUser]._user_id = 0;
        users[_idUser]._name = 0x7465737400000000000000000000000000000000000000000000000000000000;
        users[_idUser]._address = 0x5B38Da6a701c568545dCfcB03FcB870000000000000000000000000000000000;
        users[_idUser]._birth_day = 0xf711600000000000000000000000000000000000000000000000000000000000;
    }

    function getUser(uint256 user_id) external view returns (User memory) {
        return users[user_id];
    }

}

Solidity allows you to returns the struct linking it to a keywords: memory or calldata, that means the data area where variables must store.

NOTE: If you change the visibility about a specific variable to public, Solidity generate automatically a getter function and you can avoid to implement getter() functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.