深入Rust智能指针和模式匹配

目录智能指针Box堆对象分配Deref解引用Drop释放资源Rc与Arc实现1vN所有权机制Cell与RefCell内部可变性模式和匹配智能指针Box堆对象分配什么是Box?Box是一个智能指针,它在堆上分配对象。Box自动管理内存,当不再需要时会自动释

目录


智能指针

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 的组合使用

组合使用示例 BoxRc 结合使用可以实现堆上的共享所有权。 示例: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 的组合使用

BoxArc 结合使用可以实现多线程下的共享所有权。 示例: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 的组合使用

BoxRefCell 结合使用可以实现堆上的内部可变性。 示例: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 的组合使用

BoxCell 结合使用可以实现堆上的内部可变性。 示例: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),
    }
}
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
天涯学馆
天涯学馆
0x9d6d...50d5
资深大厂程序员,12年开发经验,致力于探索前沿技术!