Box<T> 指向堆上数据

Box 允许你将一份数据放在堆上而不是栈上, 留在栈上的时指向堆上数据的指针. 当指针离开作用域的时候, 它指向的数据也将被销毁.

Rust展开
12345678

fn main(){
    let a = Box::new(1);
    println!("a = {}", a);
}

// output:
// a = 1

除了将数据放在对上以外, Box没有性能损失, 但也没有其他的什么功能

常用于:

  • 在编译时大小未知时,而又需要在明确数据大小的上下文中使用这个类型值的时候

    比如: 创建递归类型时

  • 有大量数据并且希望在确保数据不被拷贝的情况下转移所有权的时候

    转移大数据的所有权可能会话费很长时间, 因为数据在栈上拷贝, 使用Box时, 只拷贝了数据的指针

  • 当希望拥有一个值并关心它的类型是否实现了某个 trait 而不是具体的类型的时候

    trait object 只关注是否实现了某个trait, 而不是具体的某个类型

Box 允许创建递归类型

Rust 在编译时需要依据类型确定数据的大小. 递归类型(recursive type)无法在编译时确定类型大小, 它的值可以是相同类型的另一个值, 这种嵌套关系理论上可以无限进行, 因此它的大小无法在编译时确定.

Box 时已知大小的, 因此在递归中使用box就可以确定类型所需要的空间.

用Rust实现的一个链表

Rust展开
1234567891011121314
#[derive(Debug)]
enum Node {
    Next(Box<Node>),
    None
}

fn main(){
  let a = Node::None;
  let b = Node::Next(Box::new(a));
  println!("b = {:?}", b);
}

//output:
// b = Next(None)

tag

usize

...

tag

None

b ^--------->-------^a

如果不使用Box则会报编译错误

PlainText展开
123456789101112
error[E0072]: recursive type `Node` has infinite size
 --> src/main.rs:2:1
  |
2 | enum Node {
  | ^^^^^^^^^ recursive type has infinite size
3 |     Next(Node),
  |          ---- recursive without indirection
  |
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Node` representable
  |
3 |     Next(Box<Node>),
  |          ++++    +

Rust编译器还贴心的告诉你该如何修复这个问题, 大赞 绝绝子

因为Box<T> 是一个指针, 编译器总是知道它的大小, 指针的大小不会随着它指向的数据量而改变.

Box<T> 实现了 Deref 因此它可以被当作引用对待, 由于它也实现了 Drop 因此当 Box<T> 离开作用域时, T 也会被销毁.

- roadup -