当前位置: 代码迷 >> 综合 >> Rust 的 Box指针
  详细解决方案

Rust 的 Box指针

热度:81   发布时间:2023-12-12 15:22:59.0

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 类型有类似的特点。