真正指向堆内存的指针被称之为所有型指针 但是Rust 也有一种 非所有型指针 - 引用 reference
- 共享引用:只读类型, Copy类型
- 可修改引用: &mut T 允许修改值
可以理解为编译的时候分别执行多读单写的检查规则
传值:函数传参的时候,转移所有权 传引用:不影响所有权传递
Rust 必须显式的 & 和 * 使用引用 , . 操作符会隐式的借用和解引用
Rust 引用可以无限的复制,编译器都会向上寻找,获取第一层地址的位置
let r: &Point = &point;
let rr: &&Point = &r;
let rrr: &&&Point = &rr;
Rust 的引用永远不会是空的, 没有默认值的引用是无法使用的
生命周期
Rust 会给每一个引用赋予一个生命周期的概念 lifetime
变量的生命周期必须包含从它那里借来的引用的生命周期
对于静态变量,其生命周期全局的,所以所有的静态变量都必须初始化,只能在unsafe 块里面修改静态变量的值 (‘static 声明周期)
static mut STASH: &i32 = &10;
fn f(p: &'static i32) {
unsafe {
STASH = p;
}
}
对于函数签名,也可以显式的定义生命周期
fn g<'a>(p: &'a i32) { ... }
let x = 10;
g(&x);
// 也可以返回一个引用
fn smallest<'a>(v: &'a [i32]) -> &'a i32 { ... }
对于结构体,其整体的生命周期就是其中生命周期最小的。当然也可以定义多个不同的周期
struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
函数签名也是类似
fn f<'a>(r: &'a i32, s: &'a i32) -> &'a i32 { r } // 可能太严苛了
fn f<'a, 'b>(r: &'a i32, s: &'b i32) -> &'a i32 { r } // 宽松多了
如果是使用的对象定义,携带self参数,那么self 的生命周期就是其返回值的生命周期。
综上,面对Rust的所有权树,携带转移和借用的逻辑,可以强迫完成线程安全的设计。
- Rust 引用 复习 (@2024-01-24)