为什么由于"添加drop-check规则时溢出"而无法实例化数据结构?

Lon*_*ong 7 rust data-structures recursive-type

这是一个我可以写下来的数据结构,它被Rust编译器接受:

pub struct Pair<S, T>(S, T);

pub enum List<T> {
    Nil,
    Cons(T, Box<List<Pair<i32, T>>>),
}
Run Code Online (Sandbox Code Playgroud)

但是,我不能写

let x: List<i32> = List::Nil;
Run Code Online (Sandbox Code Playgroud)

操场

因为Rust会抱怨"添加drop-check规则时出现溢出".为什么不可能实例化List::Nil

应该注意以下工作:

pub struct Pair<S, T>(S, T);

pub enum List<T> {
    Nil,
    Cons(T, Box<List<T>>),
}

fn main() {
    let x: List<i32> = List::Nil;
}
Run Code Online (Sandbox Code Playgroud)

操场

Pet*_*all 2

当类型尚未实例化时,编译器主要担心类型的大小在编译时是否恒定且已知,以便可以将其放置在堆栈上。如果类型是无限的,Rust 编译器会抱怨,并且通常Box通过创建子节点的间接级别来解决这个问题,子节点的大小也是已知的,因为它也装箱了自己的子节点。

但这不适用于您的类型。

当您实例化 时List<T>,变体的第二个参数的类型Cons为:

Box<List<Pair<i32, T>>>
Run Code Online (Sandbox Code Playgroud)

请注意,内部List有一个类型参数Pair<i32, T>,而不是T

该内部列表还有一个Cons,其第二个参数的类型为:

Box<List<Pair<i32, Pair<i32, T>>>>
Run Code Online (Sandbox Code Playgroud)

其中有一个Cons,其第二个参数的类型为:

Box<List<Pair<i32, Pair<i32, Pair<i32, T>>>>>
Run Code Online (Sandbox Code Playgroud)

等等。

现在这并不能完全解释为什么你不能使用这种类型。字体的大小将随着其在List结构中的深度而线性增加。当列表很短(或为空)时,它不会引用任何复杂类型。

根据错误文本,溢出的原因与丢弃检查有关。编译器正在检查该类型是否已正确删除,如果在此过程中遇到另一种类型,它将检查类型是否也已正确删除。问题是每个连续的Cons类型都包含一个全新的类型,越深入它就会变得越大,编译器必须检查每个类型是否会被正确删除。这个过程永远不会结束。