Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • 搜索未来:SEO与GEO双引擎实战手册
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • Rust 开发入门
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • 搜索未来:SEO与GEO双引擎实战手册
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • Rust 开发入门
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain

4.3 可变借用与不可变借用

在 Rust 中,借用(Borrowing)是所有权系统的一个核心机制,它允许我们临时访问一个值而不转移其所有权。借用分为两种:不可变借用(Immutable Borrow)和可变借用(Mutable Borrow)。理解这两种借用的区别以及它们之间的交互规则,是安全编写 Rust 代码的关键。

4.3.1 不可变借用

不可变借用允许你读取一个值,但不能修改它。你可以通过 & 符号创建一个不可变引用,从而实现对值的不可变借用。

示例:

fn main() {
    let s = String::from("Hello");

    // 创建不可变引用
    let len = calculate_length(&s);

    println!("The length of '{}' is {}.", s, len);
}

fn calculate_length(s: &String) -> usize {
    // s 是一个指向 String 的引用,但无法修改它
    s.len()
} // 这里 s 离开作用域,但它并不拥有所有权,所以不会发生 drop 操作

在这个例子中,calculate_length 函数通过 &s 借用了 s 的所有权,但它只能读取 s 的内容,不能修改。这保证了在借用期间,原始变量 s 仍然有效且未被意外修改。

4.3.2 可变借用

可变借用允许你读取并修改一个值。你可以通过 &mut 符号创建一个可变引用,从而实现对值的可变借用。

示例:

fn main() {
    let mut s = String::from("Hello");

    // 创建可变引用
    change(&mut s);

    println!("{}", s);
}

fn change(s: &mut String) {
    // 通过可变引用修改字符串
    s.push_str(", world!");
}

在这个例子中,change 函数通过 &mut s 借用了 s 的可变引用,并成功地向字符串追加了内容。注意,原始变量 s 必须声明为 mut,才能创建可变引用。

4.3.3 借用的核心规则

Rust 的借用规则旨在防止数据竞争(Data Races)和悬垂引用(Dangling References)。以下是两条最核心的规则:

  1. 在同一时间,你只能拥有一个可变引用,或者多个不可变引用。
  2. 引用必须始终有效。

规则一详解:

  • 多个不可变引用是允许的:因为多个读者同时读取数据是安全的,不会产生冲突。

    let s = String::from("Hello");
    let r1 = &s; // 不可变借用 1
    let r2 = &s; // 不可变借用 2
    println!("{} and {}", r1, r2); // 可以同时使用
    
  • 一个可变引用是允许的:因为只有一个写者,可以确保数据一致性。

    let mut s = String::from("Hello");
    let r1 = &mut s; // 可变借用
    // let r2 = &mut s; // 错误!不能同时有两个可变引用
    
  • 不可变引用与可变引用不能共存:因为如果存在一个读者,写者修改数据可能导致读者读到不一致的状态。

    let mut s = String::from("Hello");
    let r1 = &s; // 不可变借用
    let r2 = &mut s; // 错误!不能同时存在不可变引用和可变引用
    println!("{}", r1);
    

    编译器会报错,因为它检测到 r1(不可变引用)和 r2(可变引用)同时存在。

规则二详解:

  • 引用不能比它引用的值存活得更久。这主要涉及到生命周期(Lifetimes)的概念,但一个简单的例子可以说明:
    fn main() {
        let reference_to_nothing = dangle();
    }
    
    fn dangle() -> &String {
        let s = String::from("hello");
        &s // 返回指向局部变量 s 的引用
    } // 这里 s 离开作用域并被销毁,其内存被释放
    
    这个函数试图返回一个指向局部变量 s 的引用,但 s 在函数返回时就被销毁了,导致 reference_to_nothing 指向无效内存。Rust 编译器会拒绝这种代码,防止悬垂引用的产生。

4.3.4 借用的作用域

借用的作用域从它被创建的地方开始,一直持续到它最后一次被使用的地方。这允许我们在借用结束后,重新获得对原变量的完全控制。

示例:

fn main() {
    let mut s = String::from("Hello");

    let r1 = &s; // 不可变借用开始
    let r2 = &s; // 另一个不可变借用开始
    println!("{} and {}", r1, r2); // 最后一次使用 r1 和 r2
    // 这里 r1 和 r2 的作用域结束

    let r3 = &mut s; // 现在可以创建可变引用了
    println!("{}", r3);
}

在这个例子中,不可变引用 r1 和 r2 在 println! 之后就不再被使用,因此它们的作用域结束。之后,我们就可以安全地创建一个可变引用 r3。

4.3.5 总结

  • 不可变借用 (&T):允许多个读者同时读取数据,但不能修改。
  • 可变借用 (&mut T):允许唯一的写者读取和修改数据。
  • 核心规则:在同一时间,要么有多个不可变引用,要么有一个可变引用。引用必须始终有效。
  • 作用域:借用的作用域持续到其最后一次使用,这允许在借用结束后进行其他操作。

掌握可变与不可变借用的规则,是驾驭 Rust 所有权系统的关键一步。它帮助你在编译时就消除数据竞争,编写出既高效又安全的代码。

Last Updated:: 5/9/26, 3:13 PM