patternrustCritical
Why are recursive struct types illegal in Rust?
Viewed 0 times
structareillegalwhyrustrecursivetypes
Problem
I'm trying out random things to deepen my understanding of Rust. I just ran into the following error with this code:
The error is:
I understand that I can fix it if I put the
I would like to understand the full story behind that. I know that boxing means that it will be stored on the heap rather than the stack but I don't get why this indirection is necessary.
struct Person {
mother: Option,
father: Option,
partner: Option,
}
pub fn main() {
let susan = Person {
mother: None,
father: None,
partner: None,
};
let john = Person {
mother: None,
father: None,
partner: Some(susan),
};
}The error is:
error[E0072]: recursive type Person has infinite size
--> src/main.rs:1:1
|
1 | struct Person {
| ^^^^^^^^^^^^^ recursive type has infinite size
2 | mother: Option,
| ---------------------- recursive without indirection
3 | father: Option,
| ---------------------- recursive without indirection
4 | partner: Option,
| ----------------------- recursive without indirection
|
= help: insert indirection (e.g., a Box, Rc, or &) at some point to make Person representable
I understand that I can fix it if I put the
Person in a Box, so this works:struct Person {
mother: Option>,
father: Option>,
partner: Option>,
}
pub fn main() {
let susan = Person {
mother: None,
father: None,
partner: None,
};
let john = Person {
mother: None,
father: None,
partner: Some(Box::new(susan)),
};
}I would like to understand the full story behind that. I know that boxing means that it will be stored on the heap rather than the stack but I don't get why this indirection is necessary.
Solution
Data inside
let's compute the size:
That is, the size would have to be infinite.
Another way to look at it is just expanding
and all of this is stored inline in a single chunk of memory.
A
structs and enums (and tuples) is stored directly inline inside the memory of the struct value. Given a struct likestruct Recursive {
x: u8,
y: Option
}let's compute the size:
size_of::(). Clearly it has 1 byte from the x field, and then the Option has size 1 (for the discriminant) + size_of::() (for the contained data), so, in summary, the size is the sum:size_of::() == 2 + size_of::()That is, the size would have to be infinite.
Another way to look at it is just expanding
Recursive repeatedly (as tuples, for clarity):Recursive ==
(u8, Option) ==
(u8, Option)>) ==
(u8, Option)>)>) ==
...and all of this is stored inline in a single chunk of memory.
A
Box is a pointer, i.e. it has a fixed size, so (u8, Option>) is 1 + 8 bytes. (One way to regard Box is that it's a normal T with the guarantee that it has a fixed size.)Code Snippets
struct Recursive {
x: u8,
y: Option<Recursive>
}size_of::<Recursive>() == 2 + size_of::<Recursive>()Recursive ==
(u8, Option<Recursive>) ==
(u8, Option<(u8, Option<Recursive>)>) ==
(u8, Option<(u8, Option<(u8, Option<Recursive>)>)>) ==
...Context
Stack Overflow Q#25296195, score: 149
Revisions (0)
No revisions yet.