如何通过接口访问另一个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
相关产品推荐
相关产品推荐

