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的引用(需确保引用的值确实能存活到程序结束,否则会报错)。
相关推荐
FleetingLore20 小时前
Rust | str 常用方法
rust
一只小松许️2 天前
深入理解 Rust 的内存模型:变量、值与指针
java·开发语言·rust
m0_480502643 天前
Rust 登堂 之 Cell 和 RefCell(十二)
开发语言·后端·rust
烈风3 天前
011 Rust数组
开发语言·后端·rust
Dontla4 天前
Turbopack介绍(由Vercel开发的基于Rust的高性能前端构建工具,用于挑战传统构建工具Webpack、vite地位)Next.js推荐构建工具
前端·rust·turbopack
开心不就得了5 天前
构建工具webpack
前端·webpack·rust
ftpeak5 天前
《WebAssembly指南》第九章:WebAssembly 导入全局字符串常量
开发语言·rust·wasm
红烧code6 天前
【Rust GUI开发入门】编写一个本地音乐播放器(15. 记录运行日志)
rust·gui·log·slint
JordanHaidee6 天前
【Rust GUI开发入门】编写一个本地音乐播放器(15. 记录运行日志)
rust