Rust核心:【所有权】相关知识点

2024-02-24 08:20

本文主要是介绍Rust核心:【所有权】相关知识点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

rust在内存资源管理上采用了(先进优秀?算吗)但特立独行的设计思路:所有权。这是rust的核心,贯穿在整个rust语言的方方面面,并以此为基点来重新思考和重构软件开发体系。

涉及到的概念点:借用,引用,生命周期

借用(borrowing)

这里就要谈到这篇文章的主题,也是rust绕不开的主题:所有权。

所有权模型:Rust 的所有权模型允许值在内存中有唯一的所有者

一开始我以为:引用就是其他语言(如go)里常见的引用, 而借用是更在引用之上的一种抽象,是对我们【使用引用去达到目的】这种行为的抽象 。因为我看到在一些教程里直接将两者等同混用,但其实是不对的,
因为:Rust语言中的引用和其他语言中的引用不一样,其他语言里的引用是变量的别名,Rust语言中的引用是指向某个值的指针,而不是别名。在其他语言中,引用就相当于拿到了值的别名,跟原来的值是同一个东西,可以进行任何无差别访问。在Rust语言中的借用都是临时借用使用权,并不破坏单一所有权原则。

“借用” 是指通过引用来访问值而不获取所有权; Rust 使用 “借用” 这个术语来强调在借用期间,被借用的值的仍然归原所有者所有,并且原所有者在借用期间仍然保持可变性和原始值的所有权。
就好比我从你那里借了一本书,但我肯定不能随意在上面乱写乱画,因为书还是归你所有。所以Rust的借用默认是不可变的,如果想要修改借用的值,需要显示的声明使用可变借用&mut x(取得书主人的授权)。

通过借用而不是其他语言中的直接引用,可以确保在借用期间只有一个可变或不可变的访问者,避免了悬空指针和内存安全问题。

Rust里的借用没有开辟单独的表现方式,形式上仍然是其他语言里引用的样子:在rust里,以 变量前加“&”符来表示不可变借用,例如&x ,用&mut 表示可变借用,例如:&mut x。

从能力范围上来看: 借用包含了传统意义上的引用,但是能力范围又大于引用。注意这个图只是从能力范围上来看,可变借用和传统引用好像一样,本质还是不同的,即可变借用没有获取原始变量的所有权,就好比我租了你的房子,谈好条件可以让我装修,但房子还是你的,但在我装修房子后,你再给别的租客(别的借用)来看这个房子的时候, 这个房子会是装修好后的样子。
在这里插入图片描述
借用的限制
为了保证内存安全,Rust语言中的借用也有一些限制,比如:

  • 在同一作用域中,同一数据只能有一个可变借用,即多个可变借用不能同时存在(更准确是同一所有权型变量的多个可变借用作用域不能交叠)。
  • 在同一个作用域中,同一数据可以有多个不可变借用。
  • 在一个作用域中,可变借用与不可变借用不能同时存在 (更准确是可变借用与不可变借用的作用域不能交叠)
  • 所有借用的生命周期不能超出值的生命周期(防止悬垂指针,保证内存安全)。
  • 在有借用(包括可变借用和不可变借用)存在的情况下,不能通过原所有权型变量对值进行更新。当借用完成后(借用变量的作用域结束),物归原主,才又可以使用所有权型变量对值做更新操作了。
fn main(){let mut a = 10u32;let b = &a;a = 50;println!("{b}")
}
-----------------------
fn main(){let mut a = 10u32;let b = &mut a;a = 50;println!("{b}")
}
两个例子都不能通过编译

另外有个格外的要单独说明的点:可变引用的再赋值,会执行移动操作(而不是复制),赋值后,原来那个可变引用的变量就不能用了。可以看出:一个☝️所有权型变量的可变引用也具有所有权特征。

多级可变引用

对于多级可变引用,要利用可变引用去修改目标资源值的时候,需要做正确的多级解引用操作,比如两级引用就要对应两级接引用。而且这个引用过程中必须保证全是可变引用,才可以修改到目标资源的值。

对于多级引用的,打印语句可以为我们自动接引用到正确的层数,直至访问到目标资源值。这很符合人的意图和业务需求。

在这里有个有意思的对比:

go:
func main() {var a = 10var b = &afmt.Println(a)//output:10fmt.Println(b)//output:0x... (memory address )
}
rust:
fn main() {let a = 10u32;let b = &a;let c = &&&&&&&a;println!(a)//output:10println!(b)//output:10 println!(c)//output:10 
}

可以看到rust像gpt一样识别到了我们的人类意图,没有打印的引用的内存地址,而是打印了被引用对象的值。事实上,哪怕是像let c = &&&&&&&a这种对a的多级引用,rust也仍然正确获取了a的值。

触发所有权转移的行为

会触发所有权转移的行为有:赋值操作,函数入参,函数返回值,集合操作中的移动(如Vec、HashMap等),迭代器中的移动:

todo 补充copy trait的有关内容

Rust语言中,对于实现了Copy trait的类型,在赋值或者传参时,值会自动按位拷贝;而对于没有实现Copy trait的类型,会采用Move转移所有权的方式来传递数据。

实现了Copy trait的类型:

原生类型:整型(i8,u8,i16,u16,i32,u32,i64,u64,i128,u128,isize,usize)、浮点型(f32,f64)、布尔型、字符型(char)、单元类型()、Never Type(!)。
不可变引用(&T)
函数指针
裸指针(*const T, *mut T)
数组[T;N]、元组(T1, T2, …, Tn)、Option类型(需要注意的是:只有当它们的元素类型都实现了Copy trait时,它们才实现了Copy trait)。
对于复合类型,比如枚举体和结构体,Rust语言默认是不实现Copy trait的,但是如果这些类型的所有成员都实现了Copy trait,那么你可以手动添加#[derive(Copy, Clone)]来实现Copy trait。如果内部结构包含Move语义的类型,那么就无法实现Copy trait。

这篇关于Rust核心:【所有权】相关知识点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741512

相关文章

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

关于Maven生命周期相关命令演示

《关于Maven生命周期相关命令演示》Maven的生命周期分为Clean、Default和Site三个主要阶段,每个阶段包含多个关键步骤,如清理、编译、测试、打包等,通过执行相应的Maven命令,可以... 目录1. Maven 生命周期概述1.1 Clean Lifecycle1.2 Default Li

Rust 数据类型详解

《Rust数据类型详解》本文介绍了Rust编程语言中的标量类型和复合类型,标量类型包括整数、浮点数、布尔和字符,而复合类型则包括元组和数组,标量类型用于表示单个值,具有不同的表示和范围,本文介绍的非... 目录一、标量类型(Scalar Types)1. 整数类型(Integer Types)1.1 整数字

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始