Rust 所有权与引用

server/2025/4/2 7:30:52/

目录

    • Rust 所有权原则
      • 变量所有权
      • 变量作用范围
      • 深拷贝
    • Rust 的引用
      • 示例
      • 可变引用
      • 不可变引用
      • 可变引用和不可变引用不能同时存在
      • 悬垂引用

Rust 所有权原则

  1. Rust 中每一个值都被一个变量所拥有,该变量被称为值的所有者
  2. 一个值同时只能被一个变量所拥有,或者说一个值只能拥有一个所有者
  3. 当所有者(变量)离开作用域范围时,这个值将被丢弃

变量所有权

在 Rust 中,默认情况下赋值操作会转移所有权,而不是创建副本。例如

rust">fn main() {let s1 = String::from("hello");let s2 = s1; // s1 的所有权转移给 s2// println!("{}", s1); // ❌ 编译错误,s1 不再有效
}
  • s1 原本是 "hello" 的所有者
  • s1 赋值给 s2 后,所有权转移,s1 失效,不能再被使用

对于基本数据类型(如整数、浮点数、布尔值、字符等),Rust 采用 Copy 一个值,不会发生所有权转移

rust">fn main() {let x = 5;let y = x; // x 仍然可用,因为 i32 是 Copy 类型println!("x = {}, y = {}", x, y); // ✅ 允许
}

变量作用范围

rust">fn main() {{let s = "ss";}println!("s 的数值是 {}", s);
}

cargo check报错

rust">error[E0425]: cannot find value `s` in this scope--> src\main.rs:5:27|
5 |     println!("s 的数值是 {}", s);|                               ^|
help: the binding `s` is available in a different scope in the same function--> src\main.rs:3:13|
3 |         let s = "ss";|             ^For more information about this error, try `rustc --explain E0425`.
  • 不能在这个作用域中发现 s

简而言之,s 从创建开始就有效,然后有效期持续到它离开作用域为止

深拷贝

首先,Rust 永远也不会自动创建数据的 深拷贝 因此,任何自动的复制都不是深拷贝,可以被认为对运行时性能影响较小

  • 手动深拷贝
rust">let s1 = String::from("hello");
let s2 = s1.clone();println!("s1 = {}, s2 = {}", s1, s2);

Rust 的引用

Rust 的 引用(Reference) 是一种不拥有数据所有权的方式,它允许在不复制数据的情况下访问数据,同时确保 内存安全 和 数据一致性

引用的本质是指向某个值的地址,但它不会夺取该值的所有权,而只是借用(borrow)它

示例

rust">fn main() {let s1 = String::from("hello");let len = calculate_length(&s1); // 传递 s1 的引用println!("The length of '{}' is {}", s1, len); // ✅ s1 仍然可用
}fn calculate_length(s: &String) -> usize {s.len() // 只读访问 s
}
  • &s1 代表对 s1 的引用,但 s1 仍然是原来的所有者
  • calculate_length 只是借用 s,不会修改它,也不会夺走所有权
  • s1main 里仍然有效

可变引用

如果想修改引用的数据,需要使用可变引用(&mut T

rust">fn main() {let mut s = String::from("hello");change(&mut s); // 可变借用 sprintln!("{}", s); // ✅ "hello, world!"
}fn change(s: &mut String) {s.push_str(", world!"); // 修改 s
}

可变引用的规则

  1. 在同一时间,只能有一个可变引用(&mut T)
  2. 不能同时拥有可变引用和不可变引用(&T)

不可变引用

rust">fn main() {let s = String::from("hello");let r1 = &s; // 允许let r2 = &s; // 允许println!("{} and {}", r1, r2); // ✅ 允许多个不可变引用
}

可变引用和不可变引用不能同时存在

Rust 防止数据竞争,所以:

  • 如果存在可变引用(&mut T),就不能有不可变引用(&T)
  • 如果存在不可变引用(&T),就不能创建可变引用(&mut T)
rust">fn main() {let mut s = String::from("hello");let r1 = &s;let r2 = &s;let r3 = &mut s; // ❌ 编译错误:r1, r2 仍然有效,不能创建可变引用println!("{}, {}", r1, r2);
}

悬垂引用

rust">fn dangle() -> &String { // ❌ 编译错误let s = String::from("hello");&s // ❌ 返回局部变量的引用
} // s 被释放,引用失效
  • 这里引用值会释放掉,从而造成错误
  • Rust 检查器会报错

其中一个很好的解决方法是直接返回 String

rust">fn no_dangle() -> String {let s = String::from("hello");s // ✅ 所有权转移,数据不会被释放
}

http://www.ppmy.cn/server/180649.html

相关文章

RK3588使用笔记:系统联网配置

一、前言 话不多说,这里会介绍不同系统多种上网方式,有的是通过USB WIFI模块连接wifi信号进行网络通信,有的是通过调试电脑的网络共享,为什么要联网呢,就是为了在线更新驱动,因为离线安装会有很多依赖的问…

Python Cookbook-4.15 字典的一键多值

任务 需要一个字典,能够将每个键映射到多个值上。 解决方案 正常情况下,字典是一对一映射的,但要实现一对多映射也不难,换句话说,即一个键对应多个值。你有两个可选方案,但具体要看你怎么看待键的多个对…

第十五章:Python的Pandas库详解及常见用法

在数据分析领域,Python的Pandas库是一个不可或缺的工具。它提供了高效的数据结构和数据分析工具,使得数据处理变得简单而直观。本文将详细介绍Pandas库的基本功能、常见用法,并通过示例代码演示如何使用Pandas进行数据处理。最后,…

QScreen 捕获屏幕(截图)

一、QScreen核心能力解析 硬件信息获取 // 获取主屏幕对象 QScreen* primaryScreen QGuiApplication::primaryScreen();// 输出屏幕参数 qDebug() << "分辨率:" << primaryScreen->size(); qDebug() << "物理尺寸:" << primar…

Linux线程池实现

1.线程池实现 全部代码&#xff1a;whb-helloworld/113 1.唤醒线程 一个是唤醒全部线程&#xff0c;一个是唤醒一个线程。 void WakeUpAllThread(){LockGuard lockguard(_mutex);if (_sleepernum)_cond.Broadcast();LOG(LogLevel::INFO) << "唤醒所有的休眠线程&q…

Azure SDK 使用指南

​Azure SDK&#xff08;软件开发工具包&#xff09;是一组由微软提供的工具和库&#xff0c;旨在帮助开发者以多种编程语言&#xff08;如 .NET、Java、Python、JavaScript 等&#xff09;与 Azure 服务进行交互。 ​通过使用 Azure SDK&#xff0c;开发者可以更高效地构建、部…

VS2022 Qt 项目使用数据库报错问题

一、问题现象&#xff1a;无法解析的外部符号 "__declspec(dllimport) public: __cdecl QSqlDatabase::QSqlDatabase(void)" 定义变量QSqlDatabase db后报错信息为“无法解析的外部符号” 二 、解决步骤&#xff1a; 1、在 Visual Studio 2022 中&#xff1a;右键项…

乐鑫ESP-IDF中查看系统内存的函数大全(1)

0. 序言 项目中难免会遇到系统崩溃、内存分配失败等情况,即使没有这些异常,也要确保程序不会发生内存泄漏。因此,在代码中加入查看当前系统中内存的机制(函数)是开发时必不可少的。 乐鑫ESP-IDF中查看系统内存的接口函数众多,笔者在开发中遇到并使用到了多个。之前一直…