研读Rust圣经解析——Rust learn-12(智能指针)

本文详细介绍了Rust编程语言中的几种智能指针,包括Box<T>用于在堆上存储数据,解决递归类型问题;Rc<T>实现引用计数,允许多个所有者共享数据;RefCell<T>提供内部可变性,允许在运行时检查借用规则。此外,还讨论了Dereftrait的作用,Droptrait用于资源清理,以及如何通过这些工具实现更复杂的内存管理策略。
摘要由CSDN通过智能技术生成

智能指针

指针 (pointer)是一个包含内存地址的变量的通用概念。这个地址引用,或 “指向”(points at)一些其他数据
前面说的引用就是指针

智能指针(smart pointers)是一类数据结构,他们的表现类似指针,但是也拥有额外的元数据和功能。智能指针的概念并不为 Rust 所独有;

智能指针选择

  • Rc<T> 允许相同数据有多个所有者;Box<T>RefCell<T> 有单一所有者。
  • Box<T> 允许在编译时执行不可变或可变借用检查;Rc<T>仅允许在编译时执行不可变借用检查;RefCell<T> 允许在运行时执行不可变或可变借用检查。
  • 因为 RefCell<T> 允许在运行时执行可变借用检查,所以我们可以在即便 RefCell<T> 自身是不可变的情况下修改其内部的值。

Box<T>

是最简单最直接的智能指针,数据会被存储到堆上,且没有任何性能损失,但也没什么额为功能

使用场景

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

创建Box

如其他的方式一样都是直接new出来的

fn main() {
   
    let a = Box::new("nihao");
    println!("{}",a)
}

使用Box在堆上存储递归类型数据

首先我们先创建一个enum List

#[derive(Debug)]
enum List {
   
    Next(i32, List),
    OFF,
}

这是个递归的List,下一个节点依然可以装List
接下来使用它创建一个变量

#[derive(Debug)]
enum List {
   
    Next(i32, List),
    OFF,
}

use List::{
   Next, OFF};

fn main() {
   
    let list = Next(1, Next(2, OFF));
    println!("{:?}",list);
}

编译之后我们会发现报错,原因是:编译器认为这个类型 “有无限的大小”,所以它不知道要用多少空间存储它,或它认为这个玩意就没办法存
同时他也提供了解决方法:
在这里插入图片描述从这里可以看出,编译器希望我们使用Box来解决

解决
#[derive(Debug)]
enum List {
   
    Next(i32, Box<List>),
    OFF,
}

use List::{
   Next, OFF};

fn main() {
   
    let list = Next(1, Box::new(Next(2, Box::new(OFF))));
    println!("{:?}", list);
}

我们来解释一下为什么用Box就可以了,首先Box是将值存到了堆上,会尝试使用一个尽可能大的空间进行存储,因为 Box<T> 是一个指针,我们总是知道它需要多少空间:指针的大小并不会根据其指向的数据量而改变。因为OFF这个字段不存任何东西,自然它的大小要比Next要小,所以进行了区分,当编译器发现了一个需要空间小于正常递归空间大小的节点的时候就认为这是终止节点(其实我更喜欢叫他叶子节点,因为我常常把递归看作一个树结构)

通过 Deref trait 将智能指针当作常规引用处理

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

追踪指针的值

这里我加了一个打印y这个变量的内存地址,或许我应该说打印y这个指针的内存地址

fn main() {
   
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, *y);
    println!("{:p}",y);
}

y在这里是引用了x的值,所以y相当于一个指针,指针实际就是一个地址,要找到地址中真实的内容就需要使用解引用*
这段程序相当于

fn main() {
   
    let x = 5;
    let y = Box::new
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值