I have this contract with an array of structs:
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
contract Tickets {
struct Ticket {
uint id;
int val;
}
Ticket[] tickets;
function addTicket(uint id, int val) public returns(bool success) {
Ticket memory newTicket;
newTicket.id = id;
newTicket.val = val;
tickets.push(newTicket);
return true;
}
function getTicket(uint id) public view returns(Ticket memory) {
uint index;
for(uint i = 0; i<tickets.length; i++){
if (tickets[i].id == id) {
index = i;
break;
}
}
Ticket memory t = tickets[index];
return t;
}
function findTickets(int val) public view returns(Ticket[] memory) {
Ticket[] memory result;
for(uint i = 0; i<tickets.length; i++){
if (tickets[i].val == val) {
result.push(tickets[i]); // HERE IS THE ERROR
}
}
return result;
}
}
I need to returns a filtered by val
array but when I buil this code: result.push(tickets[i].id);
it throw this error:
TypeError: Member "push" is not available in struct Tickets.Ticket memory[] memory outside of storage.
How I can implement the filter without using push
?
To declare an array in Solidity, the data type of the elements and the number of elements should be specified. The size of the array must be a positive integer and data type should be a valid Solidity type
It’s an array, which is how Solidity tuples are returned to Javascript land. Alright, so we know that the getter is not returning a struct, per se, but rather a tuple.
Also, depending on your use cases, you might want to have the contract return the entire array and do the filtering client-side. It really depends on what you are trying to achieve and how big / difficult to filter your data is. When reading data you are still limited to gas requirements, but the user does not pay for it.
It’s an array, which is how Solidity tuples are returned to Javascript land. Alright, so we know that the getter is not returning a struct, per se, but rather a tuple. This is a big clue! When the compiler generates a getter for a mapping or an array where the element is a struct, it does something like the following:
Returning dynamic-length array of struct is still a bit tricky in Solidity (even in the current 0.8 version). So I made a little workaround to make it work even in the 0.6.
function findTickets(int val) public view returns(Ticket[] memory) {
uint256 resultCount;
for (uint i = 0; i < tickets.length; i++) {
if (tickets[i].val == val) {
resultCount++; // step 1 - determine the result count
}
}
Ticket[] memory result = new Ticket[](resultCount); // step 2 - create the fixed-length array
uint256 j;
for (uint i = 0; i < tickets.length; i++) {
if (tickets[i].val == val) {
result[j] = tickets[i]; // step 3 - fill the array
j++;
}
}
return result; // step 4 - return
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With