当前位置: 首页 > article >正文

Rust 中的引用与借用:深入理解所有权与数据安全

一、引用:不拥有数据的指针

引用本质上是一个指针,它指向一个变量的值,但不拥有该值。通过引用,我们可以在不转移所有权的情况下访问数据。

以下代码展示了如何通过引用避免转移所有权:

fn calculate_length(s: &String) -> usize {
    s.len()
}

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("The length of '{}' is {}.", s1, len);
}

关键点

  1. 在调用 calculate_length 时,我们传递了 &s1,即变量 s1 的引用。
  2. 函数参数类型为 &String,表明它接受一个引用。
  3. 引用不拥有数据,因此在函数调用后,s1 依然有效,可以继续使用。

这种机制避免了在函数间频繁地转移所有权,也减少了需要返回数据的情况。

二、借用:像借东西一样使用数据

Rust 中创建引用的行为被称为 借用。这种设计与现实生活中的借用类似:借用者可以使用所有者的数据,但不能随意修改或销毁它。

借用分为两种:

  • 不可变引用:允许读取数据,但不能修改。
  • 可变引用:允许修改数据,但同时存在一些限制。
三、可变引用:对数据的受控修改

默认情况下,Rust 中的变量和引用是不可变的。如果需要修改借用的数据,可以使用 可变引用

以下代码展示了如何使用可变引用:

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

fn main() {
    let mut s = String::from("hello");
    change(&mut s);
    println!("{}", s);
}

变化点

  1. 使用 &mut 创建可变引用。
  2. 函数签名明确表明接受一个可变引用:some_string: &mut String
  3. 可变引用允许我们修改借用的数据。
四、可变引用的限制

Rust 对可变引用有严格的规则,主要目的是避免 数据竞争(data race):

  1. 同一时间只能存在一个可变引用

    let mut s = String::from("hello");
    let r1 = &mut s;
    let r2 = &mut s; // 错误:不能同时有两个可变引用
    
  2. 不可变引用和可变引用不能同时存在

    let mut s = String::from("hello");
    let r1 = &s;
    let r2 = &mut s; // 错误:不可变引用和可变引用不能共存
    

这些限制确保了数据的修改是受控的,从而避免了潜在的并发问题。

五、作用域的技巧:灵活管理引用

引用的作用域从创建时开始,一直到最后一次使用为止。我们可以通过使用块作用域({})来显式管理引用的生命周期,从而避免冲突。

let mut s = String::from("hello");

{
    let r1 = &mut s;
    r1.push_str(", world");
} // r1 的作用域在此结束

let r2 = &mut s; // 可以安全创建新的可变引用
六、防止悬垂引用(Dangling References)

在其他语言中,指针可能会指向已经释放的内存,导致 悬垂指针 问题。而 Rust 编译器通过严格的生命周期检查,杜绝了悬垂引用的出现。例如:

fn dangle() -> &String {
    let s = String::from("hello");
    &s // 错误:s 在函数结束后会被释放
}

编译器会提示此代码无效,因为函数返回了一个指向无效内存的引用。

正确的方式是直接返回数据本身:

fn no_dangle() -> String {
    let s = String::from("hello");
    s // 所有权转移,避免悬垂引用
}
七、总结:引用与借用的核心规则
  1. 同一时间只能有一个可变引用,或多个不可变引用
  2. 引用必须始终有效

Rust 的引用与借用机制确保了内存使用的安全性,同时提供了灵活性。虽然这些规则在初学时可能会显得繁琐,但它们在防止数据竞争和提升代码健壮性方面无可替代。

通过熟练掌握引用和借用,您将能够更加高效地使用 Rust,编写出安全、优雅的代码。

延伸阅读:下一步可以学习 Rust 中的切片(Slices),它是另一种常见的引用形式,用于更细粒度地操作数据。


http://www.kler.cn/a/517639.html

相关文章:

  • macOS使用LLVM官方发布的tar.xz来安装Clang编译器
  • tmp记录
  • 基于springboot+vue的古城景区管理系统的设计与实现
  • 在Rust应用中访问.ini格式的配置文件
  • 【Rust自学】15.3. Deref trait Pt.2:隐式解引用转化与可变性
  • 矩阵快速幂
  • 多模态数据融合的基本流程与关键环节
  • elementPlus-button组件二次封装
  • LlamaV-o1:重塑大型语言模型中的逐步视觉推理
  • 最长递增——蓝桥杯
  • javaSE.类的继承
  • 2025.1.24总结
  • TMC2208替代A4988
  • 第38周:猫狗识别 (Tensorflow实战第八周)
  • Flink读写Kafka(Table API)
  • 分享14分数据分析相关ChatGPT提示词
  • 如何设计浪漫风格的壁纸
  • 低代码开发:效率革命与市场机遇
  • YOLOv10-1.1部分代码阅读笔记-model.py
  • C++入门14——set与map的使用
  • c#实现重启Explorer.exe并且启动某个命令
  • CSS 提示工具:优化网页设计,提升用户体验
  • 关于BAR(PCIE BAR或AXI BAR)的解释
  • 广西螺蛳粉:舌尖上的美食传奇
  • 【豆包MarsCode 蛇年编程大作战】蛇形烟花
  • MATLAB遗传算法求解函数最大值