Solidity:返回过滤后的结构数组,无需“推”

dri*_*nor 7 solidity

我与一组结构签订了合同:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我需要返回一个按val数组过滤的结果,但是当我构建此代码时:result.push(tickets[i].id);它会抛出此错误:

TypeError: Member "push" is not available in struct Tickets.Ticket memory[] memory outside of storage.

如何在不使用的情况下实现过滤器push

Pet*_*jda 11

在 Solidity 中返回动态长度的结构体数组仍然有点棘手(即使在当前的 0.8 版本中)。所以我做了一些解决方法,让它在 0.6 中也能工作。

  1. 确定结果计数,第 2 步将需要它。
  2. 创建固定长度数组
  3. 填充定长数组
  4. 返回固定长度数组
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
}
Run Code Online (Sandbox Code Playgroud)

  • @JuanVilar 另外,我的答案中的代码包含在“view”函数中。这意味着,它不会修改合约状态,并且可以使用“eth_call”方法从链下应用程序调用(即不需要交易)。通话无需gas,您只需为交易支付gas。因此,在这种特殊情况下,两个循环使用节点的双倍处理能力(与仅使用一个循环相比),但 Gas 成本仍然为零。 (2认同)