代码之家  ›  专栏  ›  技术社区  ›  Long

为什么不可能因为“添加删除检查规则时溢出”而实例化数据结构?[副本]

  •  7
  • Long  · 技术社区  · 7 年前

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

    pub struct Pair<S, T>(S, T);
    
    pub enum List<T> {
        Nil,
        Cons(T, Box<List<Pair<i32, T>>>),
    }
    

    但是,我不能写

    let x: List<i32> = List::Nil;
    

    playground

    因为铁锈会抱怨“在添加跌落检查规则的同时溢出”。 为什么不能实例化 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;
    }
    

    playground

    1 回复  |  直到 6 年前
        1
  •  2
  •   Peter Hall    7 年前

    当类型尚未实例化时,编译器主要担心 大小 类型为常量,在编译时已知,因此可以将其放在堆栈上。如果类型是无限的,rust编译器会发出投诉,并且 经常 Box 将通过创建子节点的间接级别来解决这一问题,该子节点的大小也是已知的,因为它也包含自己的子节点。

    但这对你的类型不适用。

    当你实例化 List<T> ,的第二个参数的类型 Cons 变量是:

    Box<List<Pair<i32, T>>>
    

    注意内部 List 有类型参数 Pair<i32, T> 不是 T .

    这个内部列表也有一个 欺骗 ,其第二个参数的类型为:

    Box<List<Pair<i32, Pair<i32, T>>>>
    

    它有一个 欺骗 ,其第二个参数的类型为:

    Box<List<Pair<i32, Pair<i32, Pair<i32, T>>>>>
    

    等等。

    现在这并不能解释为什么你不能使用这种类型。类型的大小将随其在 结构。当列表较短(或为空)时,它不引用任何复杂类型。

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

    推荐文章