Yes, it is possible to define a getter in an interface for an array of structs. Below is a complete example illustrating this.
Interface Definition
Firstly, you can define the interface with the segments function and specify Segment[] memory
as its return type.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.18;
interface IStructContract {
struct Segment {
uint256 foo;
uint256 bar;
}
// If you want to only read a single Segment at a given index then in the interface you have to explicitly destruct the Segment struct's fields in the return type,
// however you won't have to explicitly define a getter for this i.e. it'll be implicitly defined at compile time
function _segments(uint256 index) external view returns (uint256 foo, uint256 bar);
// If you want to return the entire _segments array you can declare a function with the following signature in the interface,
// however you'll have to explicitly define this function as shown in the contract below
function segments() external view returns (Segment[] memory);
}
Contract Implementation
In your contract, you can then implement this interface. Make sure to override the segments
function and ensure the return type matches with the interface, i.e. in this case Segment[] memory
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.18;
contract StructContract is IStructContract {
// You'll notice that the following variable is prepended with "_" as using "segments" gives a compile error indicating a name conflict with the "function segments()" below.
// This is quite silly imo since solidity allows for function overloading and even if they had the same name the 2 functions would still have different signatures i.e.:
// 1. function segments(uint256 index) external view;
// 2. function segments() external view;
Segment[] public override _segments;
// Note: This function can be gas-intensive with increasingly large arrays
function segments() external view override returns (Segment[] memory) {
uint256 segmentsLength = _segments.length;
Segment[] memory __segments = new Segment[](segmentsLength);
for (uint256 i = 0; i < segmentsLength; i++) {
__segments[i] = _segments[i];
}
return __segments;
}
// a simple setter for pushing a Segment onto the _segments storage variable
function addSegment(uint _foo, uint _bar) external {
Segment memory _segment = Segment({foo: _foo, bar: _bar});
_segments.push(_segment);
}
}
In this example, the contract StructContract
correctly implements the IStructContract
interface, and its segments function returns a memory array of Segment structs as expected.