原文地址:Rust 中几个智能指针的异同与使用场景
想必写过 C 的程序员对指针都会有一种复杂的情感,与内存相处的过程中可以说是成也指针,败也指针。一不小心又越界访问了,一不小心又读到了内存里的脏数据,一不小心多线程读写数据又不一致了……我知道讲到这肯定会有人觉得“出这种问题还不是因为你菜”云云,但是有一句话说得好:“自由的代价就是需要时刻保持警惕”。
Rust 几乎把“内存安全”作为了语言设计哲学之首,从多个层面(编译,运行时检查等)极力避免了许多内存安全问题。所以比起让程序员自己处理指针(在 Rust 中可以称之为 Raw Pointer),Rust 提供了几种关于指针的封装类型,称之为智能指针(Smart Pointer),且对于每种智能指针,Rust 都对其做了很多行为上的限制,以保证内存安全。
Box<T>
Rc<T> 与 Arc<T>
Cell<T>
RefCell<T>
我在刚开始学习智能指针这个概念的时候有非常多的困惑,Rust 官方教程本身对此的叙述并不详尽,加之 Rust 在中文互联网上内容匮乏,我花了很久才搞清楚这几个智能指针封装的异同,在这里总结一下,以供参考,如有错误,烦请大家指正。
以下内容假定本文的读者了解 Rust 的基础语法,所有权以及借用的基本概念:相关链接。
Box<T>
Box<T>
与大多数情况下我们所熟知的指针概念基本一致,它是一段指向堆中数据的指针。我们可以通过这样的操作访问和修改其指向的数据:
let a = Box::new(1); // Immutable
println!("{}", a); // Output: 1
let mut b = Box::new(1); // Mutable
*b += 1;
println!("{}", b); // Output: 2
然而 Box<T>
的主要特性是单一所有权,即同时只能有一个人拥有对其指向数据的所有权,并且同时只能存在一个可变引用或多个不可变引用,这一点与 Rust 中其他属于堆上的数据行为一致。
let a = Box::new(1); // Owned by a
let b = a; // Now owned by b
println!("{}