You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过接口访问另一个Solidity合约的结构体数组元素?

问题场景

我有两个独立的Solidity合约,想要通过接口访问另一个合约中结构体数组的单个元素,代码实现如下:

ContractA 代码

contract ContractA {
    struct Person {
        string name;
    }

    Person[] public persons;

    function createPerson(string memory _name) public {
        persons.push(Person(_name));
    }
}

ContractB 及接口代码

interface IContractA {
    struct Person {
        string name;
    }

    function persons(uint256 _index) external view returns (Person memory);
}

contract ContractB {
    address contractAddress = 0x3328358128832A260C76A4141e19E2A943CD4B6D;

    function getPerson(uint256 _index)
        public
        view
        returns (IContractA.Person memory)
    {
        IContractA contractAIns = IContractA(contractAddress);
        return contractAIns.persons(_index);
    }
}

调用getPerson时触发回滚错误,提示:

交易已回滚至初始状态。
注意:若发送ETH,被调用函数需为payable,且发送金额需小于当前余额。调试交易获取更多信息。

确认该错误与payable无关(已尝试添加修饰),且能正常访问数值类型变量,但无法访问结构体元素,求可行解决方法。


问题原因及解决方法

问题出在Solidity自动生成的public数组getter函数返回格式上:当数组元素是结构体类型时,Solidity默认生成的getter不会返回整个结构体,而是返回结构体的各个字段(对于仅含单个字段的Person结构体,返回值为string memory,而非Person memory)。但接口里定义的返回类型是Person memory,类型不匹配导致调用回滚。

有两种可行的解决方式:

方式一:在ContractA中手动实现结构体数组的getter函数

修改ContractA,添加一个返回整个Person结构体的函数,替代默认的自动生成getter:

contract ContractA {
    struct Person {
        string name;
    }

    Person[] public persons;

    function createPerson(string memory _name) public {
        persons.push(Person(_name));
    }

    // 手动实现getter,返回整个结构体
    function getPerson(uint256 _index) external view returns (Person memory) {
        return persons[_index];
    }
}

同时更新接口IContractA,将函数名改为手动实现的getPerson:

interface IContractA {
    struct Person {
        string name;
    }

    function getPerson(uint256 _index) external view returns (Person memory);
}

ContractB中的getPerson函数对应调整调用逻辑:

contract ContractB {
    address contractAddress = 0x3328358128832A260C76A4141e19E2A943CD4B6D;

    function getPerson(uint256 _index)
        public
        view
        returns (IContractA.Person memory)
    {
        IContractA contractAIns = IContractA(contractAddress);
        return contractAIns.getPerson(_index);
    }
}

方式二:修改接口,适配默认getter的返回格式

如果无法修改ContractA,可以调整接口,使其匹配默认getter的返回类型(单个string),再在ContractB中组装成结构体返回:

interface IContractA {
    struct Person {
        string name;
    }

    // 匹配默认getter的返回类型
    function persons(uint256 _index) external view returns (string memory);
}

contract ContractB {
    address contractAddress = 0x3328358128832A260C76A4141e19E2A943CD4B6D;

    function getPerson(uint256 _index)
        public
        view
        returns (IContractA.Person memory)
    {
        IContractA contractAIns = IContractA(contractAddress);
        // 调用默认getter获取字段,再组装成结构体返回
        string memory name = contractAIns.persons(_index);
        return IContractA.Person(name);
    }
}

内容的提问来源于stack exchange,提问作者Ali Can Almaçimeni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:32:34