Rust智能指针简介

Rust智能指针简介

说起智能指针,还得看C++,智能指针的概念就来自于C++,Rust中的智能指针用处和用法其实与C++类似。

应当首先认识到,在 Rust 中,普通引用和智能指针的一个区别是引用是一类只借用数据的指针;相反,在大部分情况下,智能指针 拥有 它们指向的数据。这里智能指针和引用相比较更多的保证了数据安全性,而不是像C++一样仅仅是实现堆上数据的RAII这么简单。

常在以下场景使用智能指针:

  • 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
  • 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
  • 当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候

智能指针对资源的管理其实还是类似于RAII那一套,在Rust里是这么描述的:

智能指针区别于常规结构体的显著特性在于其实现了 DerefDrop trait。Deref trait 允许智能指针结构体实例表现的像引用一样,这样就可以编写既用于引用、又用于智能指针的代码。Drop trait 允许我们自定义当智能指针离开作用域时运行的代码。

Deref trait

实现 Deref trait 允许我们重载 解引用运算符dereference operator*。通过这种方式实现 Deref trait 的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并用于智能指针。

use std::ops::Deref;
struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
// 实现deref trait
impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

fn main() {
    let x = 5;
    let y = MyBox::new(x);

    assert_eq!(5, x);
    //实现了deref trait,能成功解引用
    assert_eq!(5, *y);
}



最后再说一说,解引用强制转换deref coercions),这其实就是Rust 编译器实的一个类似语法糖的东西,可以让我们再在函数或方法传参上少写一些乱七八糟的符号。

//几个例子
fn hello(name: &str) {
    println!("Hello, {}!", name);
}
fn main() {
	let m = MyBox::new(String::from("Rust"));
    hello(&m);
}
//该函数接收一个&str参数,传入一个咱之前实现的MyBox引用居然可以
//原因就归功于编译器帮我们实现的解引用强制转换,转换过程大致如下
//&MyBox<String>   ->    &String    ->     &str
//如果编译器没有这个功能那么就要这么写(瞬间变丑):
let m = MyBox::new(String::from("Rust"));
hello(&(*m)[..]);

Drop Trait

Drop Trait功能和C++的析构函数如出一辙,不解释了,就是释放资源的。需要记住的是Rust会自己去在合适的时机调用drop(),所以其不允许用户自己调用drop()方法,实在想要提前释放资源,可以使用std::mem::drop.

Box< T >

Box感觉和unique_ptr比较类似,就一个单纯的用于指向堆上数据的智能指针,没有过多的特殊功能。不过由于Rust语言安全的特性,裸指针不像C/C++一样作为一等公民,所以Box还承担了一个定义未知大小类型的功能。


enum List {
    Cons(i32, Box<List>),
    Nil,
}

use crate::List::{Cons, Nil};

fn main() {
    //主要功能1,数据5位于堆上
    let p = Box<i32>::new(5);
    //主要功能2,若不使用Box,lsit大小是未知的
    let list = Cons(1,
        Box::new(Cons(2,
            Box::new(Cons(3,
                Box::new(Nil))))));
}

Rc< T >

类似上面的Box,Rc好比C++的shared_ptr,多智能指针共享一个资源,自然而然会涉及到引用计数问题,例如循环引用,与C++的shared_ptr一致,此处从略

RefCell < T >

该智能指针类似Box,但是他通过unsafe来规避的Rust的引用借用规则,是Rust提供的处理类似停机问题的无法在编译期进行代码检查的手段。

这里涉及了内部可变性等一些RefCell较复杂的原理,由于是简介这里不介绍啦。

### Rust智能指针的概念及其实现 #### 智能指针概述 在 Rust 编程语言中,智能指针不仅仅是指向数据的简单指针;它们还附加有额外的功能和行为。这些功能通常用于管理资源分配、提供更安全的操作方式或者简化复杂的数据结构处理过程[^2]。 #### Box<T> 的工作原理 当对 `Box` 类型进行解引用时,实际上是调用了其内部的方法来完成这一动作:`*(y.deref())` 。这表明了即使是对基本类型的封装,在访问实际内容之前也需要经过特定逻辑才能获取到最终值[^1]。 #### 实现细节与特性支持 为了使智能指针能够像普通引用一样被使用,Rust 提供了 `Deref` 特性,允许开发者定义自己的解引用行为。这意味着只要实现了这个特质的对象就可以自动转换成目标类型(&T 或 &mut T),从而让程序员可以更加自然地编写代码而无需关心底层的具体实现[^3]。 此外还有其他重要的智能指针如: - **Rc<T>:** 用于允许多个所有者共享同一份不可变数据; - **RefCell<T>:** 它打破了编译期借用检查器的一些限制,并提供了运行时的安全保障; - **Arc<T>:** 是线程间共享所有权的一种手段,适用于多线程环境下的并发编程需求。 对于希望创建自定义版本的人来说,则可以通过实现相应的 Traits (比如 Drop) 来控制对象生命周期结束时的行为,确保及时释放关联资源并执行必要的清理操作。 ```rust // 创建一个简单的Box实例 let b = Box::new(5); println!("b = {}", *b); // 解引用得到其中的内容 use std::rc::Rc; let rc_example = Rc::new(vec![1, 2, 3]); for _ in 0..3 { let ref_counted_value = Rc::clone(&rc_example); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值