问题描述
我正在尝试一些随机的东西来加深我对 Rust 的理解.我刚刚使用此代码遇到以下错误:
I'm trying out random things to deepen my understanding of Rust. I just ran into the following error with this code:
struct Person {
mother: Option<Person>,
father: Option<Person>,
partner: Option<Person>,
}
pub fn main() {
let susan = Person {
mother: None,
father: None,
partner: None,
};
let john = Person {
mother: None,
father: None,
partner: Some(susan),
};
}
错误是:
error[E0072]: recursive type `Person` has infinite size
--> src/main.rs:1:1
|
1 | struct Person {
| ^^^^^^^^^^^^^ recursive type has infinite size
2 | mother: Option<Person>,
| ---------------------- recursive without indirection
3 | father: Option<Person>,
| ---------------------- recursive without indirection
4 | partner: Option<Person>,
| ----------------------- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Person` representable
我知道如果 我将 Person
放在 框,所以这有效:
I understand that I can fix it if I put the Person
in a Box
, so this works:
struct Person {
mother: Option<Box<Person>>,
father: Option<Box<Person>>,
partner: Option<Box<Person>>,
}
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.
推荐答案
struct
s 和 enum
s(和元组)内的数据直接内联存储在结构值.给定一个像
Data inside struct
s and enum
s (and tuples) is stored directly inline inside the memory of the struct value. Given a struct like
struct Recursive {
x: u8,
y: Option<Recursive>
}
让我们计算大小:size_of::()
.显然它有来自 x
字段的 1 个字节,然后 Option
的大小为 1(对于判别式)+ size_of::()
(对于包含的数据),所以,总而言之,大小就是总和:
let's compute the size: size_of::<Recursive>()
. Clearly it has 1 byte from the x
field, and then the Option
has size 1 (for the discriminant) + size_of::<Recursive>()
(for the contained data), so, in summary, the size is the sum:
size_of::<Recursive>() == 2 + size_of::<Recursive>()
也就是说,大小必须是无限的.
That is, the size would have to be infinite.
另一种看待它的方式是重复扩展Recursive
(为了清晰起见,作为元组):
Another way to look at it is just expanding Recursive
repeatedly (as tuples, for clarity):
Recursive ==
(u8, Option<Recursive>) ==
(u8, Option<(u8, Option<Recursive>)>) ==
(u8, Option<(u8, Option<(u8, Option<Recursive>)>)>) ==
...
所有这些都内联存储在单个内存块中.
and all of this is stored inline in a single chunk of memory.
A Box
是一个指针,即它有固定大小,所以 (u8, Option
是 1 + 8字节.(看待 Box
的一种方式是它是一个普通的 T
,并保证它具有固定大小.)
A Box<T>
is a pointer, i.e. it has a fixed size, so (u8, Option<Box<Recursive>>)
is 1 + 8 bytes. (One way to regard Box<T>
is that it's a normal T
with the guarantee that it has a fixed size.)
这篇关于为什么递归结构类型在 Rust 中是非法的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!