35

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) {

10 Answers 10

50

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. Commented Jul 29, 2017 at 9:38
  • 1
    @PrashantPrabhakarSingh I updated the answer. Commented Nov 22, 2018 at 11:21
  • 1
    @PaulBerg again one year from now ;) any update? Commented Jun 13, 2019 at 19:13
  • 1
    @Senju It's safe to use it in Production, it's been 3 years after all Commented Jul 6, 2019 at 15:36
12

[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.

1
  • 1
    NOTE: This doesn't work for nested struct variables. You get an error: TypeError: Types containing (nested) mappings can only be parameters or return variables of internal or library functions. Commented May 3, 2023 at 11:45
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

3
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

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

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

1

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 Commented Mar 11, 2022 at 16:36
1
// 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

Now, with the new versions of solidity you can return a struct also by using memory keyword after writing struct name in return type.

Example:

 function ___(___) ____ ___ ___ returns(struct_name memory){ _________; return structInstance; } 

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.