Rust中的遞迴struct的注意點
原文連結:ofollow,noindex">https://stackoverflow.com/questions/25296195/why-are-recursive-struct-types-illegal-in-rust
我們來看一個例子吧:
struct Person { mother: Option<Person>, father: Option<Person>, partner: Option<Person>, } 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 --> recursive.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是無限大小的。
在Rust中該怎麼修復呢?上面也提示了使用Box
,Rc
,&
。 將Person
放進一個Box
,然後就正常work了。
struct Person { mother: Option<Box<Person>>, father: Option<Box<Person>>, partner: Option<Box<Person>>, } fn main() { let susan = Person { mother: None, father: None, partner: None, }; let john = Person { mother: None, father: None, partner: Some(Box::new(susan)), }; }
這背後究竟是為什麼呢?
我們都知道Rust在編譯的時候就需要知道一個型別究竟該分配多少記憶體。如果一個型別的記憶體不知道是多少的話,比如說上面的recursive就是其中一種,需要無限的空隙間,Rust就會在編譯階段直接報錯。
但是Box
是知道空間大小的,上面的例子中就在一個遞迴中插入一個box。Susan有一個mother,father和partner,他們每一個都有一個mother,father,partner……而Box使用一個指標,這個指標是固定大小動態記憶體分配的。
在structs
,enums
(tuples)中的資料是直接內聯儲存在struct值的記憶體中的。給定一個struct:
struct Recursive { x: u8, y: Option<Recursive> }
()
size_of::<Recursive>() = 2 + size_of::<Recursive>()
這個size將會變得無限的大:
Recursive == (u8, Option<Recursive>) == (u8, Option<(u8, Option<Recursive>)>) == (u8, Option<(u8, Option<(u8, Option<Recursive>)>)>) == ...
而Box<T>
是一個指標,有固定的大小的,所以(u8, Option