深入Rust智能指针和模式匹配
目录
- 智能指针
- Box堆对象分配
- Deref解引用
- Drop释放资源
- Rc与Arc实现1vN所有权机制
- Cell与RefCell内部可变性
- 模式和匹配
智能指针
Box 堆对象分配
什么是 Box?
- Box 是一个智能指针,它在堆上分配对象。
- Box 自动管理内存,当不再需要时会自动释放。
fn main() {
// 在堆上分配一个整数
let boxed_num = Box::new(42);
println!("Boxed number: {}", boxed_num); // 输出: Boxed number: 42
// 解引用
let num = *boxed_num;
println!("Unboxed number: {}", num); // 输出: Unboxed number: 42
}
Deref 解引用
什么是 Deref 特征?
- Deref 特征使得智能指针可以像普通变量一样使用。
- Deref 特征定义了如何解引用智能指针。
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let my_box = MyBox(42);
println!("MyBox value: {}", *my_box); // 输出: MyBox value: 42
}
Drop 释放资源
什么是 Drop 特征?
- Drop 特征允许在智能指针被丢弃时执行清理操作。
- Drop 特征定义了如何释放资源。
struct MyResource {
name: String,
}
impl Drop for MyResource {
fn drop(&mut self) {
println!("Dropping resource: {}", self.name);
}
}
fn main() {
{
let res = MyResource { name: String::from("Resource A") };
println!("Resource created: {}", res.name); // 输出: Resource created: Resource A
} // 在这里,资源会被自动释放
println!("After resource dropped"); // 输出: After resource dropped
}
Rc 实现 1vN 所有权机制
什么是 Rc?
- Rc(Reference Counted)是一个智能指针,用于实现共享所有权。
- Rc 通过引用计数来管理内存。
use std::rc::Rc;
fn main() {
let a = Rc::new(String::from("Hello"));
println!("Count after creating a: {}", Rc::strong_count(&a)); // 输出: Count after creating a: 1
let b = a.clone();
println!("Count after cloning a into b: {}", Rc::strong_count(&a)); // 输出: Count after cloning a into b: 2
{
let c = a.clone();
println!("Count after cloning a into c: {}", Rc::strong_count(&a)); // 输出: Count after cloning a into c: 3
} // 在这里,c 被释放,引用计数减 1
println!("Count after c goes out of scope: {}", Rc::strong_count(&a)); // 输出: Count after c goes out of scope: 2
}
Arc 实现 1vN 所有权机制
什么是 Arc?
- Arc(Atomic Reference Counted)是一个智能指针,用于实现多线程共享所有权。
- Arc 通过原子引用计数来管理内存。
use std::sync::Arc;
fn main() {
let a = Arc::new(String::from("Hello"));
println!("Count after creating a: {}", Arc::strong_count(&a)); // 输出: Count after creating a: 1
let b = a.clone();
println!("Count after cloning a into b: {}", Arc::strong_count(&a)); // 输出: Count after cloning a into b: 2
{
let c = a.clone();
println!("Count after cloning a into c: {}", Arc::strong_count(&a)); // 输出: Count after cloning a into c: 3
} // 在这里,c 被释放,引用计数减 1
println!("Count after c goes out of scope: {}", Arc::strong_count(&a)); // 输出: Count after c goes out of scope: 2
}
Cell 与 RefCell 内部可变性
什么是 Cell?
- Cell 提供了内部可变性,可以在不可变引用的情况下修改值。
- Cell 适用于单线程场景。
use std::cell::Cell;
fn main() {
let mut cell = Cell::new(0);
println!("Initial value: {}", cell.get()); // 输出: Initial value: 0
cell.set(42);
println!("New value: {}", cell.get()); // 输出: New value: 42
}
什么是 RefCell?
- RefCell 提供了内部可变性,并且支持借用检查。
- RefCell 适用于单线程场景,可以确保借用规则。
use std::cell::RefCell;
fn main() {
let mut refcell = RefCell::new(0);
println!("Initial value: {}", *refcell.borrow()); // 输出: Initial value: 0
*refcell.borrow_mut() = 42;
println!("New value: {}", *refcell.borrow()); // 输出: New value: 42
}
RefCell 与借用检查
- RefCell 支持借用检查,可以确保借用规则。
- RefCell 可以在运行时检查借用。
use std::cell::RefCell;
fn main() {
let refcell = RefCell::new(0);
{
let borrowed = refcell.borrow();
println!("Borrowed value: {}", *borrowed); // 输出: Borrowed value: 0
// 无法同时借用不可变引用和可变引用
// let borrowed_mut = refcell.borrow_mut(); // 错误
}
{
let borrowed_mut = refcell.borrow_mut();
*borrowed_mut = 42;
println!("Mutated value: {}", *borrowed_mut); // 输出: Mutated value: 42
}
}
RefCell 与多层借用
多层借用示例
- RefCell 可以嵌套使用,支持多层借用。
- 多层借用可以实现复杂的借用逻辑。
use std::cell::RefCell;
fn main() {
let outer_refcell = RefCell::new(0);
let inner_refcell = RefCell::new(outer_refcell);
{
let outer_borrowed = inner_refcell.borrow();
println!("Outer borrowed value: {}", *outer_borrowed.borrow()); // 输出: Outer borrowed value: 0
*outer_borrowed.borrow_mut() = 42;
println!("Outer mutated value: {}", *outer_borrowed.borrow()); // 输出: Outer mutated value: 42
}
{
let inner_borrowed = inner_refcell.borrow();
println!("Inner borrowed value: {}", *inner_borrowed.borrow()); // 输出: Inner borrowed value: 42
}
}
RefCell 与多线程
多线程示例
RefCell
适用于单线程场景。- 多线程场景需要使用 Mutex 或
Arc<Mutex>
。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let shared_data = Arc::new(Mutex::new(0));
let thread1_data = Arc::clone(&shared_data);
let thread2_data = Arc::clone(&shared_data);
let handle1 = thread::spawn(move || {
let mut data = thread1_data.lock().unwrap();
*data += 1;
println!("Thread 1 value: {}", *data); // 输出: Thread 1 value: 1
});
let handle2 = thread::spawn(move || {
let mut data = thread2_data.lock().unwrap();
*data += 2;
println!("Thread 2 value: {}", *data); // 输出: Thread 2 value: 3
});
handle1.join().unwrap();
handle2.join().unwrap();
println!("Final value: {}", *shared_data.lock().unwrap()); // 输出: Final value: 3
}
Box 与智能指针的组合使用
组合使用示例 Box
可以与其他智能指针结合使用,实现更复杂的功能。 示例:Box<Rc<String>>
use std::rc::Rc;
fn main() {
let boxed_string = Box::new(Rc::new(String::from("Hello")));
println!("Boxed string: {}", *boxed_string); // 输出: Boxed string: Hello
let cloned_string = boxed_string.clone();
println!("Cloned string: {}", *cloned_string); // 输出: Cloned string: Hello
}
Box 与 Rc 的组合使用
组合使用示例 Box
与 Rc
结合使用可以实现堆上的共享所有权。 示例:Box<Rc<String>>
use std::rc::Rc;
fn main() {
let boxed_string = Box::new(Rc::new(String::from("Hello")));
println!("Boxed string: {}", *boxed_string); // 输出: Boxed string: Hello
let cloned_string = Box::new(Rc::clone(&*boxed_string));
println!("Cloned string: {}", *cloned_string); // 输出: Cloned string: Hello
}
Box 与 Arc 的组合使用
Box
与 Arc
结合使用可以实现多线程下的共享所有权。 示例:Box<Arc<String>>
use std::sync::Arc;
fn main() {
let boxed_string = Box::new(Arc::new(String::from("Hello")));
println!("Boxed string: {}", *boxed_string); // 输出: Boxed string: Hello
let cloned_string = Box::new(Arc::clone(&*boxed_string));
println!("Cloned string: {}", *cloned_string); // 输出: Cloned string: Hello
}
Box 与 RefCell 的组合使用
Box
与 RefCell
结合使用可以实现堆上的内部可变性。 示例:Box<RefCell<String>>
use std::cell::RefCell;
fn main() {
let boxed_string = Box::new(RefCell::new(String::from("Hello")));
println!("Boxed string: {}", *boxed_string.borrow()); // 输出: Boxed string: Hello
*boxed_string.borrow_mut() = String::from("World");
println!("Updated string: {}", *boxed_string.borrow()); // 输出: Updated string: World
}
Box 与 Cell 的组合使用
Box
与 Cell
结合使用可以实现堆上的内部可变性。 示例:Box<Cell<String>>
use std::cell::Cell;
fn main() {
let boxed_string = Box::new(Cell::new(String::from("Hello")));
println!("Boxed string: {}", boxed_string.get()); // 输出: Boxed string: Hello
boxed_string.set(String::from("World"));
println!("Updated string: {}", boxed_string.get()); // 输出: Updated string: World
}
模式和匹配
基础模式匹配
什么是模式匹配?
- 模式匹配是一种强大的语法结构,用于分解数据结构并提取其组成部分。
- 模式匹配可以用于变量绑定、条件判断、函数参数等。
示例:基本的模式匹配
fn main() {
let point = (3, 4);
// 分解元组
let (x, y) = point;
println!("x: {}, y: {}", x, y); // 输出: x: 3, y: 4
// 匹配枚举
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
let msg = Message::Write(String::from("hello"));
match msg {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Write: {}", text),
Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b),
}
}
元组模式
元组模式用于分解元组类型的值。
fn main() {
let point = (3, 4);
// 分解元组
let (x, y) = point;
println!("x: {}, y: {}", x, y); // 输出: x: 3, y: 4
// 使用 `_` 忽略某些元素
let (x, _) = point;
println!("x: {}", x); // 输出: x: 3
}
枚举模式
枚举模式用于匹配枚举类型的值。
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::Write(String::from("hello"));
match msg {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Write: {}", text),
Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b),
}
}
结构体模式
结构体模式用于分解结构体类型的值。
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 3, y: 4 };
// 分解结构体
let Point { x, y } = point;
println!("x: {}, y: {}", x, y); // 输出: x: 3, y: 4
// 使用 `_` 忽略某些字段
let Point { x, .. } = point;
println!("x: {}", x); // 输出: x: 3
}
条件模式
条件模式允许在模式匹配中添加额外的条件。
fn main() {
let point = (3, 4);
match point {
(x, y) if x == y => println!("x and y are equal"),
(x, y) if x > y => println!("x is greater than y"),
(x, y) => println!("x: {}, y: {}", x, y),
}
}
无约束模式
无约束模式用于匹配任何值。
fn main() {
let point = (3, 4);
match point {
(x, y) @ _ => println!("x: {}, y: {}", x, y), // `@` 用于保留整个模式
}
}
列表模式
列表模式用于匹配列表类型的值。
fn main() {
let list = vec![1, 2, 3];
match list.as_slice() {
[first, second, third] => println!("First: {}, Second: {}, Third: {}", first, second, third),
[first, .., last] => println!("First: {}, Last: {}", first, last),
_ => println!("Unknown list"),
}
}
字段模式
字段模式用于匹配结构体或枚举类型的特定字段。
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 3, y: 4 };
match point {
Point { x, .. } => println!("x: {}", x), // 使用 `..` 忽略其他字段
}
}
枚举模式与字段模式
枚举模式可以结合字段模式使用。
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::Move { x: 3, y: 4 };
match msg {
Message::Move { x, .. } => println!("x: {}", x), // 使用 `..` 忽略其他字段
_ => println!("Other message"),
}
}
模式匹配与函数参数
函数参数也可以使用模式匹配。
fn print_point((x, y): (i32, i32)) {
println!("Point: ({}, {})", x, y);
}
fn main() {
let point = (3, 4);
print_point(point);
}
模式匹配与循环
循环也可以使用模式匹配。
fn main() {
let list = vec![1, 2, 3, 4];
for (index, value) in list.iter().enumerate() {
println!("Index: {}, Value: {}", index, value);
}
}
模式匹配与模式守卫
模式守卫允许在模式匹配中添加额外的条件。
fn main() {
let point = (3, 4);
match point {
(x, y) if x == y => println!("x and y are equal"),
(x, y) if x > y => println!("x is greater than y"),
(x, y) => println!("x: {}, y: {}", x, y),
}
}
模式匹配与类型约束
模式匹配可以添加类型约束。
fn main() {
let point = (3, 4);
match point {
(x, y) if x.is_positive() && y.is_positive() => println!("Both positive"),
(x, y) => println!("x: {}, y: {}", x, y),
}
}
trait Positive {
fn is_positive(&self) -> bool;
}
impl Positive for i32 {
fn is_positive(&self) -> bool {
*self > 0
}
}
模式匹配与多分支
模式匹配可以有多个分支。
fn main() {
let point = (3, 4);
match point {
(0, 0) => println!("Origin"),
(x, 0) | (0, y) => println!("On an axis"),
(x, y) => println!("General point: ({}, {})", x, y),
}
}
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。