This is interesting.
I'm not convinced that this sort of nesting is ideal for most cases because unordered lists are not useful for random access. You might find mapped structs with indexes is a little more flexible.
Are there well-solved and simple storage patterns for Solidity?
What you're asking for is workable, so I played around with it. No warranty. ;-)
pragma solidity ^0.4.18;
contract ArrayOfStructsContainsArrayOfStructs {
struct InnerStruct {
uint x;
}
struct OuterStruct {
InnerStruct[] innerStructs;
}
// This can't be public because the "free" getter is too complex for the compiler to work out a default
OuterStruct[] outerStructs;
event LogAppendedOuterStruct(address sender, uint outerStructRow);
event LogAppendedInnerStruct(address sender, uint outerStructRow, uint innerStructRow);
event LogSetInnerStructValue(address sender, uint outerStructRow, uint innerStructRow, uint value);
function appendOuterStruct() public returns(uint row) {
LogAppendedOuterStruct(msg.sender, outerStructs.length);
outerStructs.length++;
return outerStructs.length-1;
}
// The outer structs are in an array, so specify the outerStructRow
function appendInnerStruct(uint outerStructRow) public returns(uint row) {
LogAppendedInnerStruct(msg.sender, outerStructRow, outerStructs[outerStructRow].innerStructs.length);
outerStructs[outerStructRow].innerStructs.length++;
return outerStructs[outerStructRow].innerStructs.length-1;
}
function setInnerStructValue(uint outerStructRow, uint innerStructRow, uint value) public returns(bool success) {
outerStructs[outerStructRow].innerStructs[innerStructRow].x = value;
LogSetInnerStructValue(msg.sender, outerStructRow, innerStructRow, value);
return true;
}
function getInnerStructValue(uint outerStructRow, uint innerStructRow) public view returns(uint value) {
return outerStructs[outerStructRow].innerStructs[innerStructRow].x;
}
}
Hope it helps.