Box<T>
的适用场景:
- 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
- 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
- 当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候
当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
在编译时无法知道其大小的类型是递归类型(recursive type), 也即是嵌套类型, 比如链表这种数据结构
官方示例:递归类型拥有无限大小
use crate::List::{Cons, Nil};
enum List {
Cons(i32, List),
Nil,
}
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
// 编译报错:
// recursive type `List` has infinite size
那Rust是怎么计算大小的?
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
Rust 会遍历 Message 每个成员以查看 Message 哪个成员需要最多空间。
成员ChangeColor需要3个i32的空间
所以回到刚才的例子,Cons的大小根本无法推算出来;
图片.png而 Box<T>
是一个指针,指针的大小不会根据它指向的数据量而改变。
这意味着可以将 Box 放入 Cons 成员中而不是直接存放另一个 List 值.
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
图片.png
box 只提供了间接存储和堆分配;他们并没有任何其他特殊的功能
当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候 [未验证]
转移大量数据的所有权可能需要很长时间,因为数据是在堆栈上复制的。
为了在这种情况下提高性能,我们可以将堆上的大量数据存储在一个盒子中;
当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候
pub trait Draw {
fn draw(&self);
}
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
dyn关键字用于强调相关trait的方法是动态分配的
所以编译过程中是不知道具体大小的,需要用Box来修饰
网友评论