Unfortunately this is not possible. To see why, please look at how mappings are stored:
Due to their unpredictable size, mappings and dynamically-sized array types cannot be stored “in between” the state variables preceding and following them. Instead, they are considered to occupy only 32 bytes with regards to the rules above and the elements they contain are stored starting at a different storage slot that is computed using a Keccak-256 hash.
For mappings, the slot stays empty, but it is still needed to ensure that even if there are two mappings next to each other, their content ends up at different storage locations.
The value corresponding to a mapping key k
is located at keccak256(h(k) . p)
where .
is concatenation and h
is a function that is applied to the key depending on its type
In other words, the mapping values are not stored in a single place but spread at random locations all over the storage. Moreover, the compiler does not store the keys and does not track the number of items already present in the mapping so it does not even know what to copy.
This has always been problematic, which is why mappings are now disallowed in memory
structs because only other fields would actually be copied and the mapping would be silently skipped. They are still allowed in storage
structs but there's the same flaw there - a getter generated by the compiler for a public
storage variable silently skips mappings and arrays inside structs.
For arrays the workaround is to define your own function returning the struct. Then the compiler will not omit it. With mappings the problem is different so this is not enough. You would have to store the keys somewhere and then have the function copy the keys to a new struct that has an array in place of the mapping.