Rust 所有权与引用

news2025/4/2 1:29:08

目录

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

Rust 所有权原则

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

变量所有权

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

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 的所有权转移给 s2

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

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

fn main() {
    let x = 5;
    let y = x; // x 仍然可用,因为 i32 是 Copy 类型

    println!("x = {}, y = {}", x, y); // ✅ 允许
}

变量作用范围

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

cargo check报错

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 永远也不会自动创建数据的 深拷贝 因此,任何自动的复制都不是深拷贝,可以被认为对运行时性能影响较小

  • 手动深拷贝
let s1 = String::from("hello");
let s2 = s1.clone();

println!("s1 = {}, s2 = {}", s1, s2);

Rust 的引用

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

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

示例

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

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

    change(&mut s); // 可变借用 s
    println!("{}", s); // ✅ "hello, world!"
}

fn change(s: &mut String) {
    s.push_str(", world!"); // 修改 s
}

可变引用的规则

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

不可变引用

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

    let r1 = &s; // 允许
    let r2 = &s; // 允许
    println!("{} and {}", r1, r2); // ✅ 允许多个不可变引用
}

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

Rust 防止数据竞争,所以:

  • 如果存在可变引用(&mut T),就不能有不可变引用(&T)
  • 如果存在不可变引用(&T),就不能创建可变引用(&mut T)
fn main() {
    let mut s = String::from("hello");

    let r1 = &s;
    let r2 = &s;
    let r3 = &mut s; // ❌ 编译错误:r1, r2 仍然有效,不能创建可变引用

    println!("{}, {}", r1, r2);
}

悬垂引用

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2325101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探究 CSS 如何在HTML中工作

2025/3/28 向全栈工程师迈进&#xff01; 一、CSS的作用 简单一句话——美化网页 <p>Lets use:<span>Cascading</span><span>Style</span><span>Sheets</span> </p> 对于如上代码来说&#xff0c;其显示效果如下&#xff1…

Verilog中X态的危险:仿真漏掉的bug

由于Verilog中X态的微妙语义&#xff0c;RTL仿真可能PASS&#xff0c;而网表仿真却会fail。 目前进行的网表仿真越来越少&#xff0c;这个问题尤其严重&#xff0c;主要是网表仿真比RTL仿真慢得多&#xff0c;因此对整个回归测试而言成本效益不高。 上面的例子中&#xff0c;用…

使用 uv 管理 Python 项目

介绍 首先, uv 工具是使用 rust 开发出来的, 速度要比传统的 pip, pipx 等一众包管理工具要快不少. 另外, 除了包管理之外, uv 还提供了脚手架的功能, 使用体验和前端开发使用过的 vue-cli 很相似, 可以帮助我们自动初始化项目, 创建好一个空的包含必要文件结构的文件夹. 此外…

《C++11:通过thread类编写C++多线程程序》

关于多线程的概念与理解&#xff0c;可以先了解Linux下的底层线程。当对底层线程有了一定程度理解以后&#xff0c;再学习语言级别的多线程编程就轻而易举了。 【Linux】多线程 -&#xff1e; 从线程概念到线程控制 【Linux】多线程 -&#xff1e; 线程互斥与死锁 语言级别的…

19-dfs-排列数字(基础)

题目 来源 842. 排列数字 - AcWing题库 思路 由于相对简单&#xff0c;是dfs的模板题&#xff0c;具体思路详见代码 代码 #include<bits/stdc.h> using namespace std; const int N10; int state[N],path[N];//是否使用过&#xff0c;当前位置 int n; void dfs(int …

32.代码题

接着上集...... 派对&#xff1a;超时了&#xff0c;总该受到惩罚吧&#xff1f; 洛西&#xff1a;至于吗&#xff1f;就0.1秒&#xff01; 晴/宇&#xff1a;十分应该。 洛西&#xff1a;我..................... 没办法&#xff0c;洛西只能按照要求去抓R了。 1.P1102 …

nacos 3.x Java SDK 使用详解

Nacos 3.x Java SDK 使用详解 Nacos 3.x 是云原生服务治理的重要升级版本&#xff0c;其 Java SDK 在性能、协议和扩展性上均有显著优化。 一、环境要求与依赖配置 基础环境 JDK 版本&#xff1a;需使用 JDK 17&#xff08;Nacos 3.x 已放弃对 JDK 8 的支持&#xff09;。Spri…

SPI-NRF24L01

模块介绍 NRF24L01是NORDIC公司生产的一款无线通信芯片&#xff0c;采用FSK调制&#xff0c;内部集成NORDIC自己的Enhanced Short Burst 协议&#xff0c;可以实现点对点或者1对6 的无线通信,通信速率最高可以达到2Mbps. NRF24L01采用SPI通信。 ①MOSI 主器件数据输出&#xf…

python黑科技:无痛修改第三方库源码

需求不符合 很多时候&#xff0c;我们下载的 第三方库 是不会有需求不满足的情况&#xff0c;但也有极少的情况&#xff0c;第三方库 没有兼顾到需求&#xff0c;导致开发者无法实现相关功能。 如何通过一些操作将 第三方库 源码进行修改&#xff0c;是我们将要遇到的一个难点…

一区严选!挑战5天一篇脂质体组学 DAY1-5

Day 1! 前期已经成功挑战了很多期NHANES啦&#xff01;打算来试试孟德尔随机化领域&#xff5e; 随着孟德尔随机化研究的普及&#xff0c;现在孟德尔发文的难度越来越高&#xff0c;简单的双样本想被接收更是难上加难&#xff0c;那么如何破除这个困境&#xff0c;这次我打算…

自学-408-《计算机网络》(总结速览)

文章目录 第一章 计算机网络概述1. 计算机网络的定义2. 计算机网络的基本功能3. 计算机网络的分类4. 计算机网络的层次结构5. 计算机网络的协议6. 计算机网络的组成部分7. 计算机网络的应用8. 互联网的概念 物理层的主要功能第二章 数据链路层和局域网1. 数据链路层的功能2. 局…

【质量管理】纠正、纠正措施和预防的区别与解决问题的四重境界

“质量的定义就是符合要求”&#xff0c;我们在文章【质量管理】人们对于质量的五个错误观念-CSDN博客中提到过&#xff0c;这也是质量大师克劳士比所说的。“质量的系统就是预防”&#xff0c;防止出现产品不良而造成的质量损失。 质量问题的解决可以从微观和宏观两个方面来考…

新手SEO优化实战快速入门

内容概要 对于SEO新手而言&#xff0c;系统化掌握基础逻辑与实操路径是快速入门的关键。本指南以站内优化为切入点&#xff0c;从网站结构、URL设计到内链布局&#xff0c;逐层拆解搜索引擎友好的技术框架&#xff1b;同时聚焦关键词挖掘与内容策略&#xff0c;结合工具使用与…

sqli-labs靶场 less 11

文章目录 sqli-labs靶场less 11 POS联合注入 sqli-labs靶场 每道题都从以下模板讲解&#xff0c;并且每个步骤都有图片&#xff0c;清晰明了&#xff0c;便于复盘。 sql注入的基本步骤 注入点注入类型 字符型&#xff1a;判断闭合方式 &#xff08;‘、"、’、“”&…

tomcat部署项目打开是404?

问题描述 今天在帮助一个小伙伴解决问题的时候 部署成功了 就是打不开总是404 他这个项目是公司的一个18年的项目 巨老&#xff01;&#xff01;&#xff01; HTTP状态 404 - 未找到 类型 状态报告 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示…

[Linux]解决虚拟机 ubantu系统下网络的问题

问题来源&#xff1a;打开ubantu发现网络连接标识消失 解决步骤&#xff1a; 重新安装&#xff0c;前面操作无效 切换桥接模式、直连手机网络 已解决&#xff1a;

如何使用stable diffusion 3获得最佳效果

参考&#xff1a;How to get the best results from Stable Diffusion 3 Scaling Rectified Flow Transformers for High-Resolution Image Synthesis prompting SD3 不再受限于CLIP的最长77个token的长度限制&#xff0c;可以输入更长的prompt。 &#xff08;两个CLIP模型的…

Java学习笔记1——编程基础

一、整数类型变量 注意&#xff1a;每个字符型常量占两个字节 二、自动类型转换和强制类型转换 ​​​三、算术运算符 四、赋值运算符 五、比较运算符 六、逻辑运算符 七、运算符的优先级 运算符的优先级可以通过以下口诀来记忆&#xff1a; 括号优先&#xff0c;单目次之&am…

微服务核心知识点深度解析:从组件到架构设计

微服务核心知识点深度解析&#xff1a;从组件到架构设计 微服务核心知识点深度解析&#xff1a;从组件到架构设计一、Spring Cloud 5 大核心组件详解二、服务注册与发现&#xff1a;微服务的 “通讯录”概念解析Spring Cloud 中的实现 三、Nacos&#xff1a;不止是注册中心核心…

SpringBoot3+EasyExcel通过WriteHandler动态实现表头重命名

方案简介 为了通过 EasyExcel 实现动态表头重命名&#xff0c;可以封装一个方法&#xff0c;传入动态的新表头名称列表&#xff08;List<String>&#xff09;&#xff0c;并结合 WriteHandler 接口来重命名表头。同时&#xff0c;通过 EasyExcel 将数据直接写入到输出流…