Rust 的 Box指针
1 指向 Copy 类型的数据
像 i32 这样的简单类型,实现了 Copy 特性,通常数据保存在栈空间。看个简单例子,看看如何用 Box 指针封装这类数据:
fn main() {
let x: Box<i32> = Box::new(123);let y: i32 = *x;println!("{:?}, {:?}", x, y);
}
---------------------------------
>cargo run
123, 123
Box 的作用是把包装的数据变成指针。 Rust 中也有类似 C 语言的裸指针,很不安全。通常我们用 Box 实现指针的功能,可确保代码安全。
我们也可以修改 Box 指向的内容:
fn main() {
let mut x: Box<i32> = Box::new(123);*x = 456;println!("{:?}", x);
}
这与 C 语言里的指针几乎一样。
2 指向 Move 类型的数据
像 String 这样的数据类型,没有实现 Copy 特性,通常数据保存在堆空间。看个简单例子,看看如何用 Box 指针封装这类数据:
fn main() {
let x = String::from("Hello!");let y = Box::new(x);let z = *y;println!("{:?}, {:?}, {:?}", x, y, z);
}
---------------------------------
>cargo run
let x = String::from("Hello!");| - move occurs because `x` has type `String`, which does not implement the `Copy` trait
3 | let y = Box::new(x);| - value moved here
4 | let z = *y;
5 | println!("{:?}, {:?}, {:?}", x, y, z);| ^ value borrowed here after move
编译出现错误。原因是,x 没有实现 Copy 特性,let y = Box::new(x);
把 x 的值 move 入了 Box。因此,后面的 println
命令,不能再打印 x 的值了。
fn main() {
let x = String::from("Hello!");let y = Box::new(x);let z = *y;println!("{:?}, {:?}", y, z);
}
---------------------------------
>cargo run--> src\main.rs:5:28|
3 | let y = Box::new(x);| - move occurs because `y` has type `Box<String>`, which does not implement the `Copy` trait
4 | let z = y;| - value moved here
5 | println!("{:?}, {:?}", y, z);| ^ value borrowed here after move
去掉 x,仍然会出错误。原因是 let z = *y;
把 Box 包装的 String 值 move 到 z 了。换成 let z = y;
也是一样,这个参考一下 rust 的解引用机制。
继续修改一下:
fn main() {
let x = String::from("Hello!");let y = Box::new(x);println!("{:?}", y);
}
---------------------------------
>cargo run
"Hello!"
这次 Ok 了!
3 Box 的价值所在
看一个链表节点设计的例子:
struct Node {
data: i32,next: Option<Node>,
}
fn main() {
let x = Node {
data: 123,next: None,};let y = Box::new(x);println!("{:?}", y);
}
---------------------------------
>cargo run
--> src\main.rs:1:1|
1 | struct Node {
| ^^^^^^^^^^^ recursive type has infinite size
2 | data: i32,
3 | next: Option<Node>,| ------------ recursive without indirection
编译器提示需要用间接的方法实现递归定义。因为直接用 Option<Node>
,由于 Node 中存在递归定义,其大小无法确定(实际上可能是无穷大)。所以,需要用指针来代替 Node。代码修改如下:
#[derive (Debug)]
struct Node {
data: i32,next: Option<Box<Node>>,
}
fn main() {
let x = Node {
data: 123,next: None,};let y = Box::new(x);println!("{:?}", y);
}
---------------------------------
>cargo run
Node {
data: 123, next: None }
很好呀!
由于 Node 含有指针,因此也是不能 Copy 的数据类型,用 Box 封装时与 String 类型有类似的特点。