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

WHAT - 高性能和内存安全的 Rust(二)

目录

  • 1. 所有权(Ownership)
  • 2. 借用(Borrowing)
    • 不可变借用
    • 可变借用
  • 3. 可变性(Mutability)
  • 4. 作用域(Scope)
  • 综合示例

了解 Rust 的所有权(ownership)、借用(borrowing)、可变性(mutability)以及作用域(scope)是掌握 Rust 的关键。

下面通过具体的代码示例来解释这些概念。

1. 所有权(Ownership)

所有权和生命周期是 Rust 最大的特性之一,理解了也就掌握了 80% Rust 的精髓。

  • Rust 中的每一个值都有一个所有者,某个特定的变量
  • Rust 中任何一个值在任何时刻有且只有一个所有者
  • 当所有者离开作用域,值即被丢弃

以下示例展示了基本的所有权规则:

fn main() {let s1 = String::from("hello");let s2 = s1; // s1的所有权被移动到s2// println!("{}", s1); // 这行代码会报错,因为s1不再拥有这个值的所有权println!("{}", s2); // s2现在拥有这个值
}

在这个例子中,s1将其所有权移动到s2,因此s1不再有效。可以尝试在 Rust 在线工具 中运行。

首先要明确值的概念,上述例子中,字符串在堆上被分配的空间以及内容才是真正的值,而 s1s2 是指向这个值的指针,也就是所有者。由于任何一个值在任何时刻有且只有一个所有者,当执行 let s2 = s1; 后,s1 不再拥有值的所有权,因此编译会报错。

如此编译错误也可以避免生产环境的 Use-after-free 漏洞。

再来看另一个例子:

fn main() {let s1 = String::from("hello");let length = calc_length(s1);println!("length of {} is {}.", s1, length);
}fn calc_length(s: String) -> usize {s.len()
}

上述代码会编译错误。可以尝试在 Rust 在线工具 中运行。

问题出来 calc_length,执行该函数时,值的所有权已经有 s1 移交给 s,而因为当所有者离开作用域后对应的值会被丢弃,s 所指向的值就被丢弃了。

想要避免这个编译错误,我们需要把所有权移交出去:

fn main() {let s1 = String::from("hello");let (s2, length) = calc_length(s1);println!("length of {} is {}.", s2, length);
}fn calc_length(s: String) -> (String, usize) {(s, s.len())
}

很不幸,上述代码会有新的编译错误。问题出在 (s, s.len());,因为任何一个值在任何时刻有且只有一个所有者,所有执行完前面一半代码后,(s, s 的所有权已经移交出去了,再执行后一半,s.len()),就会报错,因为 s 在这一刻就不存在了。

继续优化代码:

fn main() {let s1 = String::from("hello");let (s2, length) = calc_length(s1);println!("length of {} is {}.", s2, length);
}fn calc_length(s: String) -> (String, usize) {let length = s.len();(s, length)
}

2. 借用(Borrowing)

上述第二个例子的代码出现一个问题:只想要获取字符串长度,却需要将所有权转移两次。因此,Rust 提供了另外一个重要的概念:借用。

借用是指通过引用传递数据,而不是通过值传递。Rust 区分可变借用和不可变借用。

不可变借用

fn main() {let s1 = String::from("hello");let len = calculate_length(&s1);println!("The length of '{}' is {}.", s1, len);
}fn calculate_length(s: &String) -> usize {s.len() // 借用s,不会改变所有权
}

在这个例子中,calculate_length函数借用了s1的不可变引用,因此calculate_length函数不能修改s1的值。

可变借用

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

在这个例子中,change函数借用了s的可变引用,因此可以修改s的值。

由于 Rust 对所有权以及引用有严格的控制,因此 Rust 在任何时间可以准确知晓引用的数量,因此 Rust 可以对引用使用类似读锁(共享锁)以及写锁(排他锁)的控制。换句话说,Rust 中的任何值:

  1. 在任意时间,要么只有一个可变引用(排他锁),要么只能有多个不可变引用(共享锁)
  2. 引用必须总是有效的

上述特性在多线程编程尤为重要,可以很大程度保证代码的线程安全,并且由于这些分析发生在编译时,Rust 可以避免为了保证线程安全带来的额外性能开销。

3. 可变性(Mutability)

Rust 中变量默认是不可变的,需要显式地使用 mut 关键字声明可变变量。

fn main() {let mut x = 5;println!("The value of x is: {}", x);x = 6;println!("The value of x is: {}", x);
}

在这个例子中,x被声明为可变的,因此可以修改其值。

4. 作用域(Scope)

作用域决定了变量在程序中的生命周期。变量一旦离开作用域,其值会被自动销毁。

Rust 和大部分编程语言类似,值的作用域是离它的声明最近的一对花括号中间。

fn main() {{let s = String::from("hello"); // s在这个作用域内有效println!("{}", s);} // 这里s离开作用域并被销毁// println!("{}", s); // 这行代码会报错,因为s已经超出了作用域
}

在这个例子中,s的作用域仅限于花括号内部,一旦超出作用域,s会被销毁,无法再访问。

综合示例

下面的示例综合展示了所有权、借用、可变性和作用域:

fn main() {let mut s = String::from("hello");{let r1 = &s; // 不可变借用let r2 = &s; // 不可变借用println!("r1: {}, r2: {}", r1, r2);} // r1和r2在这里离开作用域{let r3 = &mut s; // 可变借用r3.push_str(", world");println!("r3: {}", r3);} // r3在这里离开作用域println!("s: {}", s);
}

这个例子展示了如何在不同作用域内进行不可变和可变借用,以及如何在作用域结束时自动释放借用。

通过这些示例,可以更好地理解Rust中的所有权、借用、可变性和作用域的基本概念。

相关文章:

WHAT - 高性能和内存安全的 Rust(二)

目录 1. 所有权(Ownership)2. 借用(Borrowing)不可变借用可变借用 3. 可变性(Mutability)4. 作用域(Scope)综合示例 了解 Rust 的所有权(ownership)、借用&am…...

办理河南建筑工程乙级设计资质的流程与要点

办理河南建筑工程乙级设计资质的流程与要点 办理河南建筑工程乙级设计资质的流程与要点主要包括以下几个方面: 流程: 工商注册与资质规划:确保企业具有独立法人资格,完成工商注册,并明确乙级设计资质的具体要求&…...

分类算法和回归算法区别

分类算法和回归算法在机器学习中扮演着不同的角色,它们的主要区别体现在输出类型、应用场景以及算法目标上。以下是对两者区别和使用场景的详细分析: 一、区别 1.输出类型: 分类算法:输出是离散的类别标签,通常表示为…...

利用Frp实现内网穿透(docker实现)

文章目录 1、WSL子系统配置2、腾讯云服务器安装frps2.1、创建配置文件2.2 、创建frps容器 3、WSL2子系统Centos服务器安装frpc服务3.1、安装docker3.2、创建配置文件3.3 、创建frpc容器 4、WSL2子系统Centos服务器安装nginx服务 环境配置:一台公网服务器&#xff08…...

怎么用Excel生成标签打印模板,自动生成二维码

环境: EXCEL2021 16.0 问题描述: 怎么用excel生成标签打印模板自动生成二维码 解决方案: 在Excel中生成标签打印模板并自动生成二维码,可以通过以下几个步骤完成: 1. 准备数据 首先,确保你的Excel表…...

java基于ssm+jsp 美食推荐管理系统

1前台首页功能模块 美食推荐管理系统,在系统首页可以查看首页、热门美食、美食教程、美食店铺、美食社区、美食资讯、我的、跳转到后台等内容,如图1所示。 图1前台首页功能界面图 用户注册,在注册页面可以填写用户名、密码、姓名、联系电话等…...

数据分析:置换检验Permutation Test

欢迎大家关注全网生信学习者系列: WX公zhong号:生信学习者Xiao hong书:生信学习者知hu:生信学习者CDSN:生信学习者2 介绍 置换检验是一种非参数统计方法,它不依赖于数据的分布形态,因此特别适…...

【React】使用Token做路由权限控制

在components/AuthRoute/index.js中 import { getToken } from /utils import { Navigate } from react-router-domconst AuthRoute ({ children }) > {const isToken getToken()if (isToken) {return <>{children}</>} else {return <Navigate to"/…...

机器学习周记(第四十四周:Robformer)2024.6.17~2024.6.23

目录 摘要ABSTRACT1 论文信息1.1 论文标题1.2 论文摘要1.3 论文引言1.4 论文贡献 2 论文模型2.1 问题描述2.2 Robformer2.2.1 Encoder2.2.2 Decoder 2.3 鲁棒序列分解模块2.4 季节性成分调整模块 摘要 本周阅读了一篇利用改进 Transformer 进行长时间序列预测的论文。论文模型…...

JAVA学习笔记DAY10——SpringBoot基础

文章目录 SpringBoot3 介绍SpringBoot 快速入门SpringBootApplication SpringBoot 配置文件统一配置管理Yaml 配置优势tips SpringBoot 整合 SpringMVC静态资源拦截器 interceptor SpringBoot 整合 DruidSpringBoot 整合 MybatisSpringBoot 整合 tx aopSpringBoot 打包 SpringB…...

如何在Android中实现多线程与线程池?

目录 一、Android介绍二、什么是多线程三、什么是线程池四、如何在Android中实现多线程与线程池 一、Android介绍 Android是一种基于Linux内核的开源操作系统&#xff0c;由Google公司领导开发。它最初于2007年发布&#xff0c;旨在为移动设备提供一种统一、可扩展的操作系统。…...

SCI绘图【1】-不同颜色表示密度和差异--密度图

参考资料&#xff1a;密度图&#xff08;Density Plot&#xff09; - 数据可视化图表 - 数字孪生百科 密度图是快速观察变量数值分布的有效方法之一。通常情况下&#xff0c;会根据两个变量将平面绘图区域分为非常多的子区域&#xff0c;之后以不同颜色表示落在该区域上样本的…...

C语言 while循环1

在C语言里有3种循环&#xff1a;while循环 do while 循环 for循环 while语句 //while语法结构 while&#xff08;表达式&#xff09;循环语句; 比如在屏幕上打印1-10 在while循环中 break用于永久的终止循环 在while循环中&#xff0c;continue的作用是跳过本次循环 …...

[C++][数据结构][LRU Cache]详细讲解

目录 1.什么是LRU Cache&#xff1f;2.LRU Cache实现 1.什么是LRU Cache&#xff1f; LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用&#xff0c;它是一种Cache替换算法。什么是 Cache&#xff1f; 狭义的Cache指的是位于CPU和主存间的快速RAM 通常它不像系统…...

怎样激励员工积极应用新版FMEA培训后的知识?

在快节奏的职场环境中&#xff0c;新版FMEA&#xff08;失效模式与影响分析&#xff09;的培训无疑是提升员工技能、优化工作流程的重要一环。然而&#xff0c;如何让员工积极地将所学知识应用于实际工作中&#xff0c;却是一个值得深入探讨的问题。下面&#xff0c;深圳天行健…...

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统&#xff0c;而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备&#xff0c;并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线…...

React useEffect 执行时机

默认情况下&#xff0c;Effect 在每次渲染&#xff08;包括初始渲染&#xff09;后运行。 如果 React 的所有依赖项都与上次渲染时的值相同&#xff0c;则将跳过本次 Effect。 useEffect(() > {// 这里的代码会在每次渲染后执行 });useEffect(() > {// 这里的代码只会在…...

centos7 根目录扩容

1、先检查一下磁盘空间 [rootlocalhost ~]# lsblk 二、使用fdisk创建新分区 [rootlocalhost ~]# fdisk /dev/vdb 1、输入 p &#xff0c;查看当前分区表&#xff1b; 2、输入 n &#xff0c;新建一个分区&#xff1b; 3、再输入 p &#xff0c;选择分区类型为主分区&#x…...

为什么要做Redis分区和分片

Redis分区&#xff08;Partitioning&#xff09;和分片&#xff08;Sharding&#xff09;是将数据分布在多个Redis实例或多个节点上的做法。这种技术用于提高性能、可扩展性和可用性。以下是执行Redis分区和分片的主要原因&#xff1a; 1. **提高吞吐量**&#xff1a; - 通…...

电脑不小心删除的文件怎么恢复?4个必备恢复方法!

“刚刚在对电脑里的某些垃圾文件进行清理时&#xff0c;我一不小心误删了比较重要的数据。这些误删的数据还有机会恢复吗&#xff1f;希望大家帮帮我&#xff0c;非常感谢&#xff01;” 在这个数字化飞速发展的时代&#xff0c;电脑早已成为我们日常生活和工作中不可或缺的一部…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...