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较复杂的原理,由于是简介这里不介绍啦。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Rust是一种系统级编程语言,其设计的核心是所有权(Ownership)和生命周期(Lifetime),这两个概念确保了内存安全并避免了空指针异常。以下是Rust所有权规则的主要要点: 1. **所有权**:每个值在任何时候只能被一个变量拥有。这意味着Rust中的每一个值都有一个明确的所有者,一旦所有权转移,原所有者对该值就不再有任何权利。 2. **生命周期**:生命周期描述了一个变量在其作用域内存在的时间段。当一个变量的生命周期结束,其拥有的值也会自动销毁,以防止悬挂引用(dangling references)。 3. **移动(Move)**:值传递默认是移动(move),这意味着当一个变量的值转移给另一个变量时,原始变量会失去对那块内存的访问,而不是复制。 4. **借用(Borrowing)**:对于暂时需要某个变量的内容但不希望转移所有权的情况,可以使用借用。Rust提供了`&`和`&mut`两种借用方式,分别是常量借用(不可变)和可变借用(可修改)。 5. **引用(References)**:`&T`是Rust的引用语法,它可以指向T类型的值,但不会改变所有者。引用本身也有生命周期,它必须活得比所指向的值更长。 6. **生命周期关联**:Rust通过生命周期标记(lifetime annotations)来管理引用的生命周期,确保引用在引用值存在期间始终有效。 7. **智能指针(Smart Pointers)**:如`Rc`(引用计数)和`Arc`(原子引用计数)用于处理共享所有权,以及`Box`和`Vec`的内部实现。 8. **析构函数(Destructors)**:当一个值离开作用域或所有权转移时,析构函数会被调用,执行清理工作。 **相关问题--:** 1. Rust中如何处理不同生命周期的变量? 2. 为何Rust强调移动而不是复制? 3. 何时使用`Rc`和`Arc`,它们的区别是什么?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值