RustPrimer
  • Introduction
  • 初识Rust
  • 安装Rust
    • Linux
    • Mac
    • Windows
    • 版本管理工具: rustup
  • 编辑器
    • 前期准备
    • vim
    • emacs
    • vscode
    • atom
    • sublime
    • visual studio
    • spacemacs
  • Rust快速入门
    • Rust旅程
    • 变量绑定与原生类型
    • 数组、动态数组和字符串
    • 结构体与枚举
    • 控制流
    • 函数与方法
    • 特性
    • 注释与文档
    • 输入输出流
  • Cargo项目管理器
  • 基本程序结构
    • 注释
    • 条件
    • 循环
  • 类型、运算符和字符串
    • 基础类型
    • 复合类型
    • 字符串类
    • 基础运算符和字符串格式化
  • 函数
    • 函数参数
    • 函数返回值
    • 语句和表达式
    • 高阶函数
  • 模式匹配
    • match关键字
    • 模式 pattern
  • 特征 Trait
    • trait关键字
    • trait对象
  • 泛型
  • 可变性、所有权、租借和生命期
    • 所有权
    • 引用和借用
    • 生命周期
  • 闭包
    • 闭包的语法
    • 闭包的实现
    • 闭包作为参数和返回值
  • 集合类型 Collections
    • 动态数组 Vec
    • 哈希表 HashMap
  • 迭代器
    • 迭代器、适配器、消费者
  • 模块和包系统、Prelude
    • 模块 module 和包 crate
    • Prelude
  • Option、Result与错误处理
  • 输入与输出
  • 宏系统
  • 堆、栈与Box
  • 几种智能指针
    • Rc, Arc
    • Mutex, RwLock
    • Cell, RefCell
  • 类型系统中的几个常见 Trait
    • Into/From 及其在 String 和 &str 互转上的应用
    • AsRef, AsMut
    • Borrow, BorrowMut, ToOwned
    • Deref 与 Deref coercions
    • Cow 及其在 String 和 &str 上的应用
  • Send 和 Sync
  • 并发,并行,多线程编程
    • 线程
    • 消息传递
    • 共享内存
    • 同步
    • 并行
  • Unsafe、原始指针
    • Unsafe
    • 原始指针
  • FFI
    • rust调用ffi函数
    • 将rust编译成库
  • 运算符重载
  • 属性和编译器参数
    • 属性
    • 编译器参数
  • Cargo参数配置
  • 测试与评测
    • 测试 (testing)
    • 评测 (benchmark)
  • 代码风格
  • Any与反射
  • 安全(safe)
  • 常用数据结构实现
    • 栈结构
    • 队列
    • 二叉树
    • 优先队列
    • 链表
    • 图结构
  • 标准库介绍
    • 系统命令:调用grep
    • 目录操作:简单grep
    • 网络模块:W回音
  • 实战篇
    • 实战:Json处理
    • 实战:Web 应用开发入门
    • 实战:使用Postgresql数据库
  • 附录-术语表
Powered by GitBook
On this page
  • Rc
  • Rc Weak
  • Arc
  • Arc Weak
  • 一个例子

Was this helpful?

  1. 几种智能指针

Rc, Arc

Rust 建立在所有权之上的这一套机制,它要求一个资源同一时刻有且只能有一个拥有所有权的绑定或 &mut 引用,这在大部分的情况下保证了内存的安全。但是这样的设计是相当严格的,在另外一些情况下,它限制了程序的书写,无法实现某些功能。因此,Rust 在 std 库中提供了额外的措施来补充所有权机制,以应对更广泛的场景。

默认 Rust 中,对一个资源,同一时刻,有且只有一个所有权拥有者。Rc 和 Arc 使用引用计数的方法,让程序在同一时刻,实现同一资源的多个所有权拥有者,多个拥有者共享资源。

Rc

Rc 用于同一线程内部,通过 use std::rc::Rc 来引入。它有以下几个特点:

  1. 用 Rc 包装起来的类型对象,是 immutable 的,即 不可变的。即你无法修改 Rc<T> 中的 T 对象,只能读;

  2. 一旦最后一个拥有者消失,则资源会被自动回收,这个生命周期是在编译期就确定下来的;

  3. Rc 只能用于同一线程内部,不能用于线程之间的对象共享(不能跨线程传递);

  4. Rc 实际上是一个指针,它不影响包裹对象的方法调用形式(即不存在先解开包裹再调用值这一说)。

例子:

use std::rc::Rc;

let five = Rc::new(5);
let five2 = five.clone();
let five3 = five.clone();

Rc Weak

Weak 通过 use std::rc::Weak 来引入。

Rc 是一个引用计数指针,而 Weak 是一个指针,但不增加引用计数,是 Rc 的 weak 版。它有以下几个特点:

  1. 可访问,但不拥有。不增加引用计数,因此,不会对资源回收管理造成影响;

  2. 可由 Rc<T> 调用 downgrade 方法而转换成 Weak<T>;

  3. Weak<T> 可以使用 upgrade 方法转换成 Option<Rc<T>>,如果资源已经被释放,则 Option 值为 None;

  4. 常用于解决循环引用的问题。

例子:

use std::rc::Rc;

let five = Rc::new(5);

let weak_five = Rc::downgrade(&five);

let strong_five: Option<Rc<_>> = weak_five.upgrade();

Arc

Arc 是原子引用计数,是 Rc 的多线程版本。Arc 通过 std::sync::Arc 引入。

它的特点:

  1. Arc 可跨线程传递,用于跨线程共享一个对象;

  2. 用 Arc 包裹起来的类型对象,对可变性没有要求;

  3. 一旦最后一个拥有者消失,则资源会被自动回收,这个生命周期是在编译期就确定下来的;

  4. Arc 实际上是一个指针,它不影响包裹对象的方法调用形式(即不存在先解开包裹再调用值这一说);

  5. Arc 对于多线程的共享状态几乎是必须的(减少复制,提高性能)。

示例:

use std::sync::Arc;
use std::thread;

fn main() {
    let numbers: Vec<_> = (0..100u32).collect();
    let shared_numbers = Arc::new(numbers);

    for _ in 0..10 {
        let child_numbers = shared_numbers.clone();

        thread::spawn(move || {
            let local_numbers = &child_numbers[..];

            // Work with the local numbers
        });
    }
}

Arc Weak

与 Rc 类似,Arc 也有一个对应的 Weak 类型,从 std::sync::Weak 引入。

意义与用法与 Rc Weak 基本一致,不同的点是这是多线程的版本。故不再赘述。

一个例子

下面这个例子,表述的是如何实现多个对象同时引用另外一个对象。

use std::rc::Rc;

struct Owner {
    name: String
}

struct Gadget {
    id: i32,
    owner: Rc<Owner>
}

fn main() {
    // Create a reference counted Owner.
    let gadget_owner : Rc<Owner> = Rc::new(
        Owner { name: String::from("Gadget Man") }
    );

    // Create Gadgets belonging to gadget_owner. To increment the reference
    // count we clone the `Rc<T>` object.
    let gadget1 = Gadget { id: 1, owner: gadget_owner.clone() };
    let gadget2 = Gadget { id: 2, owner: gadget_owner.clone() };

    drop(gadget_owner);

    // Despite dropping gadget_owner, we're still able to print out the name
    // of the Owner of the Gadgets. This is because we've only dropped the
    // reference count object, not the Owner it wraps. As long as there are
    // other `Rc<T>` objects pointing at the same Owner, it will remain
    // allocated. Notice that the `Rc<T>` wrapper around Gadget.owner gets
    // automatically dereferenced for us.
    println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
    println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);

    // At the end of the method, gadget1 and gadget2 get destroyed, and with
    // them the last counted references to our Owner. Gadget Man now gets
    // destroyed as well.
}
Previous几种智能指针NextMutex, RwLock

Last updated 5 years ago

Was this helpful?