- 第1节:Rust 介绍
- 第2节:Rust 安装
- 第3节:Rust Hello,world!
- 第4节:Rust Hello,Cargo!
- 第5节:Rust 栈和堆
- 第6节:Rust 测试
- 第7节:Rust 条件编译
- 第8节:Rust 文档
- 第9节:Rust 迭代器
- 第10节:Rust 并发性
- 第11节:Rust 错误处理
- 第12节:Rust 外部函数接口
- 第13节:Rust Borrow 和 AsRef
- 第14节:Rust 发布通道
- 第15节:Rust 变量绑定
- 第16节:Rust 函数
- 第17节:Rust 基本类型
- 第18节:Rust 注释
- 第19节:Rust if
- 第20节:Rust for 循环
- 第21节:Rust while 循环
- 第22节:Rust 所有权
- 第23节:Rust 引用与借用
- 第24节:Rust 生存期
- 第25节:Rust 可变性
- 第26节:Rust 结构体
- 第27节:Rust 枚举
- 第28节:Rust 匹配
- 第29节:Rust 模式
- 第30节:Rust 方法语法
- 第31节:Rust 向量
- 第32节:Rust 字符串
- 第33节:Rust 泛型
- 第34节:Rust 特征
- 第35节:Rust 降
- 第36节:Rust if let
- 第37节:Rust 特征的对象
- 第38节:Rust 闭包
- 第39节:Rust 通用函数调用语法
- 第40节:Rust 箱和模块
- 第41节:Rust “常量”和“静态”
- 第42节:Rust 属性
- 第43节:Rust type 别名
- 第44节:Rust 类型转换
- 第45节:Rust 关联类型
- 第46节:Rust 全类型
- 第47节:Rust 操作符和重载
- 第48节:Rust 'Deref'强制转换
- 第49节:Rust 宏命令
- 第50节:Rust 原始指针
- 第51节:Rust unsafe
Rust 原始指针
原始指针
Rust 在标准库有许多不同的智能指针类型,但是有两种特别的类型。Rust 的安全来自于编译时检查,但原始指针没有这样的保证,使用起来不安全。
*const T 和 *mut T 在 Rust 中被称为“原始指针”。有时,当写库的某些类型时,出于某种原因你需要绕过 Rust 的安全保证。在这种情况下,你可以使用原始指针来实现你的库,同时为给用户一个安全接口。例如,允许 * 指针起别名,允许他们被用来写共享类型,甚至线程安全共享内存类型( Rc和 Arc 类型在 Rust 中都被完全实现)。
这里要记住原始指针与其他指针类型是不同的地方。他们:
- 不能保证指有效内存,甚至不保证非空(不像 Box 和 & );
- 不像 Box ,没有任何自动清理功能,所以需要手动管理资源;
- 是原始旧数据,也就是说,他们不转移指向,不像 Box ,因此 Rust 编译器不能防止像 use-after-free 一样的漏洞;
- 与 & 不用,缺乏任何形式的生命周期,所以编译器无法推断悬空指针;
- 不能保证别名使用或者易变性,不同于直接通过 *const T 不能产生变化。
Basics
创建一个原始指针是绝对安全的:
let x = 5;
let raw = &x as *const i32;
let mut y = 10;
let raw_mut = &mut y as *mut i32;
然而,非关联化的指针是不安全的。这是行不通的:
let x = 5;
let raw = &x as *const i32;
println!("raw points at {}", *raw);
它会给出这样的错误:
error: dereference of unsafe pointer requires unsafe function or block [E0133]
println!("raw points at{}", *raw);
^~~~
原始指针废弃时,你承担这样的后果,那就是它不指向那个正确的地方。因此,你需要 unsafe:
let x = 5;
let raw = &x as *const i32;
let points_at = unsafe { *raw };
println!("raw points at {}", points_at);
要了解更多关于原指针的操作,请看 API 文档。
FFI
对 FFI 来说原指针是很有用的:Rust 的 *const T 和 *mut T 与 C 的 const T 和 T 是相似的。更多关于它的使用,请看 FFI 章节。
引用和原始指针
在运行时,一个原始指针 * 和一个指向同一块数据的引用具有相同的表示。事实上,一个 &T 引用将隐式强制转换为安全代码中的 *const T 原始指针并且与常量 mut 相似(两种强制转换可以显式地被执行,值分别是 const T 和 mut T)。
相反,从 const 指向引用 & 是不安全的。 &T 总是有效的,因此至少,原始指针 const T 必须指向一个 T 类型的有效实例。此外,由此产生的指针必须满足引用的别名使用和可变性规则。编译器假定这些属性对任何引用都是真的,不管他们是如何创建的,因此任何从原始指针的转换都认为它们有这些属性。程序员必须保证这一点。
推荐的转换方法是
let i: u32 = 1;
// explicit cast
let p_imm: *const u32 = &i as *const u32;
let mut m: u32 = 2;
// implicit coercion
let p_mut: *mut u32 = &mut m;
unsafe {
let ref_imm: &u32 = &*p_imm;
let ref_mut: &mut u32 = &mut *p_mut;
}
&*x 解除引用要使用 transmute。transmute 是非常强大的,更受限制的操作也能正确使用;例如,它要求 x 是一个指针(而不像 transmute)。