真正指向堆内存的指针被称之为所有型指针 但是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)