我知道Box是一个在堆上分配的智能指针。所以我可以使用Box将一个原始的堆栈分配数组转换为一个“动态”堆分配数组。但是在创建一个数据结构方面,比如说一个树,为什么我需要Box指针呢?
lvjbypge1#
与C中的指针不同,Box<T>不能为空。它总是持有一个指向T的非空指针。Option<Box<T>>代表了指向堆分配对象的 * 可空 * 指针的概念。如果你把一个普通的Box<T>存储在一个T中,那么每个对象都将包含一个指向另一个不同对象的非空指针,如果没有空性,并且Box<T>必然是非循环的,那么你最终会得到一个无限大的数据结构。
Box<T>
T
Option<Box<T>>
ia2d9nvy2#
如果struct,enum或union直接或间接包含自身,而不使用某种指针,则大小必须是无限的,这是不可能的。通过使用Option<Box<T>>,您只在实际需要时才分配更多空间。
struct
enum
union
2q5ifsrm3#
Box指针用于确定递归类型的大小。
Box
enum List{ // Cons refers to List itself // since this is a recursive type its size cannot be determined at compile time Cons(i32,List), Nil, }
由于递归的原因,Rust无法计算出它需要存储多少空间,因此我们编写如下代码:
#[derive(Debug)] enum List{ // Cons is similar to a linked list Cons(i32,Box<List>), Nil, }
现在编译器知道列表类型只有i32和固定大小的Box指针。当我们使用List枚举定义列表变量时
let list_var=Cons(1,Box::new(Cons(10,Box::new(Cons(100,Box::new(Nil))))));
这里的问题是每次我们创建Cons变量时,我们都用Box Package 它,即使我们必须写Nil . 'Nil is something that has no associated value but with wrapping it with Box'指针,我们仍然分配堆空间,这是不必要的。
Nil
is something that has no associated value but with wrapping it with
enum List{ // we avoid allocating heap space for Nil // Option's None will replace Nil Cons(i32, Option<Box<List>>), // Nil, we remove this }
之后,我将这样初始化list_var
list_var
// instead of Box::new(Nil) I am using None let list_var=List::Cons(1,Some(Box::new(Cons(10,Some(Box::new(Cons(100,None)))))));
3条答案
按热度按时间lvjbypge1#
与C中的指针不同,
Box<T>
不能为空。它总是持有一个指向T
的非空指针。Option<Box<T>>
代表了指向堆分配对象的 * 可空 * 指针的概念。如果你把一个普通的
Box<T>
存储在一个T
中,那么每个对象都将包含一个指向另一个不同对象的非空指针,如果没有空性,并且Box<T>
必然是非循环的,那么你最终会得到一个无限大的数据结构。ia2d9nvy2#
如果
struct
,enum
或union
直接或间接包含自身,而不使用某种指针,则大小必须是无限的,这是不可能的。通过使用Option<Box<T>>
,您只在实际需要时才分配更多空间。2q5ifsrm3#
Box
指针用于确定递归类型的大小。由于递归的原因,Rust无法计算出它需要存储多少空间,因此我们编写如下代码:
现在编译器知道列表类型只有i32和固定大小的Box指针。当我们使用List枚举定义列表变量时
这里的问题是每次我们创建Cons变量时,我们都用
Box
Package 它,即使我们必须写Nil
. 'Nilis something that has no associated value but with wrapping it with
Box'指针,我们仍然分配堆空间,这是不必要的。之后,我将这样初始化
list_var