rust 智能指针(一)

简介: rust 智能指针

智能指针

Box

Box 的使用场景

由于 Box 是简单的封装,除了将值存储在堆上外,并没有其它性能上的损耗。而性能和功能往往是鱼和熊掌,因此 Box 相比其它智能指针,功能较为单一,可以在以下场景中使用它:

  • 特意的将数据分配在堆上
  • 数据较大时,又不想在转移所有权时进行数据拷贝
  • 类型的大小在编译期无法确定,但是我们又需要固定大小的类型时
  • 特征对象,用于说明对象实现了一个特征,而不是某个特定的类型
Box 堆对象分配

因为 Box 允许你将一个值分配到堆上,然后在栈上保留一个智能指针指向堆上的数据。

当栈上数据转移所有权时,实际上是把数据拷贝了一份,最终新旧变量各自拥有不同的数据,因此所有权并未转移。

fn main() {
    let a = Box::new(3);
    println!("a = {}", a); // a = 3
    // 下面一行代码将报错
    // let b = a + 1; // cannot add `{integer}` to `Box<{integer}>`
    //正确
    //let b = *a + 1
}
}
将动态大小类型变为 Sized 固定大小类型

Rust 需要在编译时知道类型占用多少空间,如果一种类型在编译时无法知道具体的大小,那么被称为动态大小类型 DST。

其中一种无法在编译时知道大小的类型是递归类型:在类型定义中又使用到了自身,或者说该类型的值的一部分可以是相同类型的其它值,这种值的嵌套理论上可以无限进行下去,所以 Rust 不知道递归类型需要多少空间:

enum List {
    Cons(i32, List),
    Nil,
}

以上就是函数式语言中常见的 Cons List,它的每个节点包含一个 i32 值,还包含了一个新的 List,因此这种嵌套可以无限进行下去,Rust 认为该类型是一个 DST 类型,并给予报错:

error[E0072]: recursive type `List` has infinite size //递归类型 `List` 拥有无限长的大小
 --> src/main.rs:3:1
  |
3 | enum List {
  | ^^^^^^^^^ recursive type has infinite size
4 |     Cons(i32, List),
  |               ---- recursive without indirection

此时若想解决这个问题,就可以使用我们的 Box:

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

只需要将 List 存储到堆上,然后使用一个智能指针指向它,即可完成从 DST 到 Sized 类型(固定大小类型)的华丽转变。

Box 中还提供了一个非常有用的关联函数:Box::leak,它可以消费掉 Box 并且强制目标值从内存中泄漏,读者可能会觉得,这有啥用啊?

fn main() {
   let s = gen_static_str();
   println!("{}", s);
}
fn gen_static_str() -> &'static str{
    let mut s = String::new();
    s.push_str("hello, world");
    Box::leak(s.into_boxed_str())
}
特征对象

在 Rust 中,想实现不同类型组成的数组只有两个办法:枚举和特征对象,前者限制较多,因此后者往往是最常用的解决办法。

trait Draw {
    fn draw(&self);
}
struct Button {
    id: u32,
}
impl Draw for Button {
    fn draw(&self) {
        println!("这是屏幕上第{}号按钮", self.id)
    }
}
struct Select {
    id: u32,
}
impl Draw for Select {
    fn draw(&self) {
        println!("这个选择框贼难用{}", self.id)
    }
}
fn main() {
    let elems: Vec<Box<dyn Draw>> = vec![Box::new(Button { id: 1 }), Box::new(Select { id: 2 })];
    for e in elems {
        e.draw()
    }
}
Box::leak

Box 中还提供了一个非常有用的关联函数:Box::leak,它可以消费掉 Box 并且强制目标值从内存中泄漏,读者可能会觉得,这有啥用啊?

其实还真有点用,例如,你可以把一个 String 类型,变成一个 'static 生命周期的 &str 类型:

fn main() {
   let s = gen_static_str();
   println!("{}", s);
}
fn gen_static_str() -> &'static str{
    let mut s = String::new();
    s.push_str("hello, world");
    Box::leak(s.into_boxed_str())
}

Deref 解引用

智能指针的名称来源,主要就在于它实现了 Deref 和 Drop 特征,这两个特征可以智能地帮助我们节省使用上的负担:

Deref 可以让智能指针像引用那样工作,这样你就可以写出同时支持智能指针和引用的代码,例如 *T

Drop 允许你指定智能指针超出作用域后自动执行的代码

常规引用的解引用。

常规引用是一个指针类型,包含了目标数据存储的内存地址。对常规引用使用 * 操作符,就可以通过解引用的方式获取到内存地址对应的数据值:

fn main() {
    let x = 5;
    let y = &x;
    assert_eq!(5, x);
    assert_eq!(5, *y);
}

这里 y 就是一个常规引用,包含了值 5 所在的内存地址,然后通过解引用 *y,我们获取到了值 5。如果你试图执行 assert_eq!(5, y);,代码就会无情报错,因为你无法将一个引用与一个数值做比较:

error[E0277]: can't compare `{integer}` with `&{integer}` //无法将{integer} 与&{integer}进行比较
 --> src/main.rs:6:5
  |
6 |     assert_eq!(5, y);
  |     ^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}`
  |
  = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
                    // 你需要为{integer}实现用于比较的特征PartialEq<&{integer}>
智能指针解引用

实现 Deref 后的智能指针结构体,就可以像普通引用一样,通过 * 进行解引用,例如 Box 智能指针:

fn main() {
    let x = Box::new(1);
    let sum = *x + 1;
}

智能指针 x 被 * 解引用为 i32 类型的值 1,然后再进行求和。

定义自己的智能指针

由于 Box 本身很简单,并没有包含类如长度、最大长度等信息,因此用一个元组结构体即可。

struct MyBox<T>(T);
impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

跟 Box 一样,我们的智能指针也持有一个 T 类型的值,然后使用关联函数 MyBox::new 来创建智能指针。由于还未实现 Deref 特征,此时使用 * 肯定会报错:

fn main() {
    let y = MyBox::new(5);
    assert_eq!(5, *y);
}

运行后,报错如下:

error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
  --> src/main.rs:12:19
   |
12 |     assert_eq!(5, *y);
   |                   ^^


rust 智能指针(二)https://developer.aliyun.com/article/1391760

相关文章
|
安全 程序员 编译器
C++中的RAII(资源获取即初始化)与智能指针
C++中的RAII(资源获取即初始化)与智能指针
173 0
|
安全 程序员 C++
C++中的智能指针:从原始指针到现代内存管理
C++中的智能指针:从原始指针到现代内存管理
115 0
|
C++
C++:一文读懂智能指针
C++:一文读懂智能指针
226 0
|
消息中间件 Kubernetes NoSQL
智能指针的种类以及使用场景
智能指针的种类以及使用场景
|
安全 C++
c++11新特性——智能指针详解
c++11新特性——智能指针详解
|
安全 C++ 容器
C++中的智能指针:自动内存管理的利器
C++中的智能指针:自动内存管理的利器
147 0
|
Rust 安全 编译器
30天拿下Rust之智能指针
30天拿下Rust之智能指针
91 1
|
Rust 安全 开发者
Rust的安全特性概览:守护内存安全与空指针的终结者
Rust作为一种系统级编程语言,以其独特的内存安全特性和对空指针的严格管理,为开发者提供了更加稳健和安全的编程环境。本文将对Rust的内存安全机制、空指针处理策略以及其他安全特性进行概览,旨在展示Rust如何帮助开发者构建更加安全和可靠的软件系统。
|
存储 Rust C++
C++智能指针
【2月更文挑战第14天】介绍C++智能指针
98 0

热门文章

最新文章