Rust中的智能指针与并发编程
立即解锁
发布时间: 2025-09-04 01:50:45 阅读量: 9 订阅数: 32 AIGC 


Rust编程核心概念精讲
### Rust 中的智能指针与并发编程
#### 1. 指针与智能指针概述
在 Rust 中,指针是存储另一个变量地址的变量。例如,我们创建变量 `x` 和 `y`,分别存储整数值 10 和 20,再创建变量 `x_p` 作为 `x` 的引用,`x_p` 就存储了 `x` 的地址。以下是示例代码:
```rust
fn main() {
let x = 10;
let y = 20;
let x_p = &x;
println!("x = {}, &x = {:p}", x, &x);
println!("y = {}, &y = {:p}", y, &y);
println!("x_p = {:p}", x_p);
}
```
Rust 中最常见的指针类型是引用,它们只是借用所指向的值,没有额外的功能。而智能指针不仅表现得像指针,还具有额外的功能和元数据。智能指针通常使用结构体实现,它们拥有数据而不是借用数据。智能指针实现了 `Deref` 和 `Drop` 特性,这使得它们变得“智能”。`Deref` 特性允许智能指针结构体实例表现得像引用,`Drop` 特性允许你编写自定义代码,当智能指针实例超出作用域时执行。Rust 标准库中最常见的智能指针有 `Box<T>`、`Rc<T>` 和 `RefCell<T>`。
#### 2. Box<T> 智能指针
`Box<T>` 也称为盒子,是 Rust 中最简单的智能指针,它允许你将数据存储在堆上,栈上只包含指向堆上数据的指针。以下是使用 `Box<T>` 将值存储在堆上的示例:
```rust
fn main() {
let x = Box::new(10.5);
println!("x = {}", x);
}
```
当变量 `x` 超出作用域时,栈上的盒子和堆上的相应数据会被释放。另外,Rust 不允许定义在编译时大小未知的类型,递归类型就是这样的例子。例如:
```rust
enum A {
B(i32),
C(i32, A),
}
fn main() {
let a = A::C(1, A::C(2, A::B(3)));
}
```
这段代码会报错,因为 Rust 编译器在编译时无法确定枚举类型 `A` 的大小。解决方法是在 `C` 的声明中使用 `Box<A>` 代替 `A`:
```rust
enum A {
B(i32),
C(i32, Box<A>),
}
fn main() {
let x = A::C(1, Box::new(A::C(2, Box::new(A::B(3)))));
let sz = std::mem::size_of_val(&x);
println!("size of x = {}", sz);
}
```
这样,编译器就能计算出变体 `C` 的大小,因为无限递归被消除了。
#### 3. Rc<T> 智能指针
`Rc<T>` 或引用计数智能指针允许数据有多个所有者。它会跟踪对一个值的引用数量,如果引用计数降为零,那么该值不再被使用,可以安全地从内存中清理。它是单线程的引用计数智能指针。以下是一个示例:
```rust
enum A {
B(i32),
C(i32, Rc<A>),
}
use std::rc::Rc;
fn main() {
let x = Rc::new(A::C(1, Rc::new(A::C(2, Rc::new(A::B(3)))));
println!("count of x = {}", Rc::strong_count(&x));
let _y = A::C(5, Rc::clone(&x));
println!("count of x = {}", Rc::strong_count(&x));
{
let _z = A::C(10, Rc::clone(&x));
println!("count of x = {}", Rc::strong_count(&x));
}
println!("count of x = {}", Rc::strong_count(&x));
}
```
在这个例子中,最初 `x` 的引用计数是 1,然后随着 `_y` 和 `_z` 共享它,引用计数增加到 3。当 `_z` 超出作用域时,引用计数又减少 1。
#### 4. RefCell<T> 智能指针
`RefCell<T>` 遵循内部可变性模式,允许你即使在有不可变引用的情况下也能修改数据。它表示单一所有权,类似于 `Box<T>`。Rust 的借用规则允许你有一个可变引用或任意数量的不可变引用,这些引用必须始终有效。对于引用和 `Box<T>`,这些规则的不变性在编译时强制执行,而对于 `RefCell<T>`,则在运行时强制执行。一个常见的使用方式是将 `RefCell<T>` 与 `Rc<T>` 结合使用。以下是示例代码:
```rust
#[derive(Debug)]
enum A {
B(i32),
C(Rc<RefCell<i32>>, Rc<A>),
}
use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let x = Rc::new(RefCell::new(10));
let y = Rc::new(A::C(Rc::clone(&x), Rc::new(A::B(1))));
println!("y = {:?}", y);
*x.borrow_mut() += 100;
println!("y mutated = {:?}", y);
}
```
在这个例子中,我们创建了一个 `Rc<RefCell<i32>>
0
0
复制全文
相关推荐










