Rust中所有权和作用域及生命周期

在 Rust 中,作用域(Scope)所有权(Ownership) 是保证内存安全的核心机制,它们共同决定了变量的生命周期和内存管理方式,无需垃圾回收即可避免悬垂指针、双重释放等内存问题。

概念 含义 是否自动触发销毁 示例
作用域 (Scope) 变量的可访问范围 ✅ 是 { let x = 1; }
所有权 (Ownership) 资源的唯一持有者 ✅ 是 let s = String::from("hi");
生命周期 (Lifetime) 引用的有效区间 N/A &'a str

作用域

作用域是 一个变量(或引用、资源)在程序中 有效、可访问 的代码范围 ,由一对花括号 {}界定:

  1. 确定性:作用域由代码结构显式界定,编译期即可确定,不存在运行时动态变化。
  2. 自动清理 :变量离开作用域时,Rust 会自动调用其drop方法(若实现drop trait,则会调用 drop函数),释放内存或资源(如文件句柄、网络连接等)。
  3. 嵌套性:作用域可以嵌套(内部作用域包含在外部作用域中),内部作用域可访问外部作用域的实体,但外部作用域无法访问内部作用域的实体。
事件 发生时机 结果
变量绑定 let语句执行时 内存分配(如需要)
变量可见 声明点到作用域结束 可在作用域内访问
变量销毁 离开作用域时 调用 drop释放资源

变量销毁顺序

  1. 后进先出(LIFO):与声明顺序相反
  2. 结构体字段:按声明顺序销毁
  3. 数组元素:从第一个到最后一个

所有权

Rust不使用垃圾回收(GC),而是通过所有权系统在编译期保证内存安全 (在编译时会进行一系列的规则检查,在运行时零开销):

  • 每个值(资源)在任意时刻只有一个所有者(owner);
  • 当所有者离开作用域时,值会被自动销毁;
  • 赋值或传参会移动(move)所有权,除非实现了copy trait。

引用与借用

为避免 频繁的 所有权转移,Rust 提供引用机制:

  • 不可变引用(&T):只读访问,允许多个同时存在;
  • 可变引用(&mut T):可修改数据,同一作用域内仅允许一个。

借用规则:

  • 引用作用域不能超过被引用变量的作用域(防悬垂引用);
  • 同一数据不能同时存在可变和不可变引用。

赋值

赋值会引起两种语义:

  • 复制(Copy)a 仍然可以使用;
    • 隐式浅拷贝:若类型实现 Copy trait(如整数、浮点、布尔、字符、元组中全是 Copy 类型) ,则赋值时为Copy语义,不会转移所有权;
    • Clone(显式深拷贝):会同时复制堆数据;
  • 所有权转移(Move)a 不再有效。

Copy类型

类型类别 示例 特点
标量类型(scalar) i32, u64, f32, bool, char 小且固定大小,在栈上
全是 Copy 类型的元组 (i32, i32), (u8, f64, bool) 只要里面的每个字段都是 Copy
指针类(少见) *const T, *mut T原生指针) 不涉及所有权
函数指针 fn(i32) -> i32 也是 Copy

非Copy类型

类型类别 示例 说明
堆分配类型 String, Vec<T>, Box<T> 包含堆内存指针
动态大小类型 &str, [T], Rc<T> 内部有引用计数或指针
用户定义结构体 若字段中含非 Copy 成员 整体就不是 Copy
其他智能指针 Rc<T>, Arc<T>, RefCell<T> 有运行时管理逻辑

生命周期

生命周期(Lifetime)是编译器用来确保引用始终有效的核心机制。它们解决了"悬垂引用"问题------确保引用不会指向已释放的内存。生命周期是引用有效的作用域范围,由编译器在编译时进行静态分析,不产生运行时开销:** **

  • 引用在使用时是合法的;
  • 不会悬空(dangling reference);
  • 不会同时存在冲突的可变/不可变引用。

生命周期参数用 'a, 'b 等表示(撇号 '声明生命周期参数),用法类似于泛型参数 ( 在大多数情况下,Rust 会自动推断生命周期):

  • 'a 并不改变运行逻辑;
  • 只是告诉编译器:"这些引用之间的关系"。
场景 必须明确标注的情况 可以省略的情况
结构体 包含引用类型的字段(无论多少个) 不包含引用字段(无需生命周期参数)
普通函数 1. 多个引用参数且返回引用 1. 无返回引用 2. 单个引用参数且返回引用
方法 1. 返回引用来自外部参数(非 self) 2. 多个外部引用参数且返回引用 1. 返回引用来自 self 2. 无返回引用
Trait / 枚举 包含引用类型的关联项或方法参数 / 返回值 不包含引用类型的关联项或方法

结构体

当结构体包含引用时,必须为这些引用标注生命周期,以确保结构体的生命周期不超过它所包含的引用的生命周期。

若结构体的多个引用来自不同生命周期,可用多个参数区分

rust 复制代码
// 两个字段的生命周期不同,分别用'a和'b标注
struct Article<'a, 'b> {
    content: &'a str, // 内容的生命周期为'a
    source: &'b str,  // 来源的生命周期为'b
}

fn main() {
    let content = String::from("Rust lifecycle intro");
    let source = "Wikipedia"; // 字符串字面量,生命周期为'static
    
    let art = Article {
        content: &content,
        source: &source,
    };
    // art的生命周期受限于'a(content的生命周期)和'b(source的生命周期)中较短的一个
}

函数

函数的参数或返回值如果是引用类型,可能需要标注生命周期。

省略规则:编译器有3条生命周期推断规则,允许在常见场景中省略显式注解:

  • 每个引用参数获取自己的生命周期参数
rust 复制代码
fn foo(x: &i32)         // 隐式:fn foo<'a>(x: &'a i32)
fn foo(x: &i32, y: &i32) // 隐式:fn foo<'a, 'b>(x: &'a i32, y: &'b i32)
  • 若只有一个输入生命周期参数,它被赋予所有输出生命周期参数;
rust 复制代码
fn bar(x: &str) -> &str // 隐式:fn bar<'a>(x: &'a str) -> &'a str
  • 若有多个输入生命周期参数,但其中一个是&self &mut self,则self的生命周期将赋予所有输出周期参数
rust 复制代码
impl<'a> ImportantExcerpt<'a> {
    fn announce(&self, announcement: &str) -> &str {
        // 隐式:fn announce<'b>(&'a self, announcement: &'b str) -> &'a str
        println!("注意:{}", announcement);
        self.part
    }
}

必须明确标注的情况:当函数的返回引用可能来自多个输入引用,或编译器无法推断返回引用的来源时,必须手动标注生命周期:

  • 多个输入引用参数,且返回引用
rust 复制代码
// 正确示例:标注生命周期'a,说明x、y和返回值共享同一生命周期
// 注解'a表示:返回的引用必须来自x或y,且其生命周期不超过x和y中生命周期较短的那个。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

静态生命周期

'static是一个特殊的生命周期,表示引用可以存活到整个程序运行期间。常见:

  • 字符串字面量 :存储在程序的只读内存中,生命周期为'static
  • 显式声明为'static的引用(需确保引用的值确实能存活到程序结束,否则会报错)。
相关推荐
DongLi012 天前
rustlings 学习笔记 -- exercises/05_vecs
rust
番茄灭世神2 天前
Rust学习笔记第2篇
rust·编程语言
shimly1234562 天前
(done) 速通 rustlings(20) 错误处理1 --- 不涉及Traits
rust
shimly1234562 天前
(done) 速通 rustlings(19) Option
rust
@atweiwei2 天前
rust所有权机制详解
开发语言·数据结构·后端·rust·内存·所有权
shimly1234562 天前
(done) 速通 rustlings(24) 错误处理2 --- 涉及Traits
rust
shimly1234563 天前
(done) 速通 rustlings(23) 特性 Traits
rust
shimly1234563 天前
(done) 速通 rustlings(17) 哈希表
rust
shimly1234563 天前
(done) 速通 rustlings(15) 字符串
rust
shimly1234563 天前
(done) 速通 rustlings(22) 泛型
rust