Rust Ownership基本概念

2023-10-28 15:20
文章标签 rust 基本概念 ownership

本文主要是介绍Rust Ownership基本概念,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

引言:

1.Ownership原则

2.数据的安全性

3.变量赋值

3.1 简单标量,复杂变量的赋值情况

3.2 函数传参与返回值

4.引用类型

5.切片类型(slice type)

summery:


引言:

自学Rust的时候感觉Ownership的概念需要记录一下,方便复习。

首先Rust采用Ownership这个概念是为了使其达到Rust所谓的安全性。在有了C/C++编程基础之后,大部分概念理解起来还是很快的,但是有关于Ownership的概念就大相径庭。当初学c的时候,学到指针,就出现了很多问题,同样在Rust上,有关于数据在内存中的创建、访问、修改和清除,体现了Rust语言的核心概念。

Rust没有使用垃圾回收器,也就是不让用户手动释放一个空间,而是采用一个作用空间(scope)的机制,当一个变量退出作用空间之后,其对应内存就会被释放。这点其实在c/c++中也是有的,就是变量离开{ }之后,其占用的内存就会被回收。但是Rust的Ownership使得除这个机制以外不在需要类似free的操作。那么就有一个问题:当一个作用空间很长({ }中的变量使用了很多内存,如较大的结构体),那么Rust如何将不在使用的变量所占用的空间回收?Rust要求每个数据只有一个Owner,这个owner我理解为就是访问到内存上数据的方式,比如:rust不允许多个指针同时指向一个数据。为什么有了ownership就只需要scope,就能完成空间清理?接下来就是rust官方rust编程语言手册中对ownership的说明。

1.Ownership原则

1)rust中的的数值都有一个变量名,称为owner

2)同一时间,数据只能有一个owner

3)当owner离开作用区间(scope)的时候,数据占用的内存会被清除

对于第三条的演示:

      

     可以看到打印x处,被标红,rust语言支持包检测到了语法错误。

2.数据的安全性

在C/C++中除了const类型,其他的变量都是可以被修改的,但是在rust中除了const这种类型特性没什么区别意外,多了mutable和immutable前缀。如果不声明为mut变量,rust中默认为immutable,及不可变。其特性是在初始化之后不能被修改,但是和const不一样的是,immutable变量是可以重新定义的,之前定义的同名变量会被隐去无法访问。这一点在c/c++中是没有的,如果在c中对一个一个变量定义多次,会有重定义报错。如果加了mut前缀,那么该变量就和c/c++中的一般变量声明和修改就很相似了。一下是示例:

            

a是一个immutable变量,直接修改其值就会检查出语法错误,但是27行对其重定义,甚至修改数据类型都是可以的。

b是一个mut变量,可以直接修改值也可以进行类型转换。

3.变量赋值

3.1 简单标量,复杂变量的赋值情况

在rust中赋值有三种:复制,传值,克隆

区分开这些操作的原因是,内存被分为堆和栈,简单数据类型会直接存入栈中,对于拥有这种数据的owner使用的赋值都是复制。复制之后会有多个逻辑相等的变量。

传值操作是对于那种复杂数据而言,比如string。存储这种数据不仅需要栈来存储简单数值(长度和只想数据实体的指针)还需要堆存储较大的数据实体。完成船只操作就是将数据的owner转移到另一个owner上,以前的owner(即变量名)就不能再使用了!这一点与c/c++区别很大,因为c系语言是允许多个不同名指针指向同一份数据的。在rust中完成传值操作后,仅仅是将栈中的数据进行复制,而指针指向堆中的数据实体是同一个,旧的owner此时会失效。

以下是示例:

         

传值过程如上左图所示,检验s1已经不可用,看上右图,发现打印s1就会有语法错误,s1已经不能再访问数据实体。

克隆操作,就是对堆栈数据完全复制过程,如下图所示:

         

3.2 函数传参与返回值

函数的参数传递,本质上也是赋值过程,完全遵照3.1的三种赋值规则。对于简单标量类型的参数如fn call i32(..)->i32{ ...}这样的函数,没必要讨论。但是问题出在复杂数据类型的传值赋值过程。如果是在c/c++中会创建一个新的参变量,函数返回后会将这个参变量占用的内存回收。但是rust的源数据传给函数参数之后,原owner就不能访问这个变量了,然后随着函数返回,参数owner会超出作用空间,从而引起源数据被抹除。也就是说像c/c++那样进行操作的话,变量被函数调用一次时候就不能再用了!有一个简单的操作就是,在函数返值中将参数传回,这样在调用者定义一个新的变量来接收返回值,就可以保证源数据能传递下来。从这个过程可以看出第一章“原则2”被贯彻的的很清楚。

以下是使用传值(move)进行参数赋值的函数调用示例,该函数功能是获取字符串长度的中值。

 

4.引用类型

可以发现3.2中使用传值进行函数参数赋值的操作有点蠢。那么类似c语言中的指针参数或者c++中的引用参数,rust也给出了一种引用类型前缀&。但是看到这里本人就有一个疑问,如果一个owner被多个引用类型引用,是否打破了只有一个owner的原则。然后rust编程语言手册上紧跟着就有说明,引用类型也分为mutable(let _s = &mut s)和immutable(let _s = &s)。对于后者可以有任意多个引用变量,它可以访问数据实体,但是不能修改数据实体。前者是每个变量只允许拥有一个mut 引用,该类型的引用可以修改数据实体,但是必须在其他引用的访问操作完成之后才可以使用(为的是保证之前的引用访问的数据是有效的),给一个例子:

在上左图,企图在打印_s1之前创建一个可变引用,出现了一个语法错误。而在右图,在所有的不可变引用完成操作之后创建可变引用就是被允许的。

回归函数调用引用类型,由于owner没有进入被调函数的函数体,即不存在owner随着调用结束而超出作用空间,所以源数据占用的内存不会被回收。以下给出示例:

5.切片类型(slice type)

切片类型是为了获取复杂数据类型数据的一部分,

let s_slice = &s;//let s_slice = &s[..];//let s_slice = &s[..n];//let s_slice = &s[n..];//let s_slice = &s[n..m];

切片类型可以引用一部分也可以引用全部,但是切片类型都是不可变引用,let s_slice = &mut s;这种是有语法错误的。

summery:

在ownership的三条原则下建立的开辟内存,访问内存,操作内存数据,回收内存机制,使得rust具有更高的安全性,实际上就是把c/c++中运行时可能出现的空指针操作等问题在编译时期就给检测出来。

 

这篇关于Rust Ownership基本概念的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【Rust练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m

【机器学习】高斯网络的基本概念和应用领域

引言 高斯网络(Gaussian Network)通常指的是一个概率图模型,其中所有的随机变量(或节点)都遵循高斯分布 文章目录 引言一、高斯网络(Gaussian Network)1.1 高斯过程(Gaussian Process)1.2 高斯混合模型(Gaussian Mixture Model)1.3 应用1.4 总结 二、高斯网络的应用2.1 机器学习2.2 统计学2.3

linux中使用rust语言在不同进程之间通信

第一种:使用mmap映射相同文件 fn main() {let pid = std::process::id();println!(

第二十四章 rust中的运算符重载

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust中的运算符重载 目录 注意一、前言二、基本使用三、常用运算符四、通用约束 一、前言 C/C++中有运算符重载这一概念,它的目的是让即使含不相干的内容也能通过我们自定义的方法进行运算符操作运算。 比如字符串本身是不能相加的,但由于C++中的String重载了运算符+,所以我们就可以将两个字符串进行相加、但实际

【Rocketmq入门-基本概念】

Rocketmq入门-基本概念 名词解释名称服务器(NameServer)消息队列(Message Queue)主题(Topic)标签(Tag)生产者(Producer)消费者(Consumer)拉取模式(Pull)推送模式(Push)消息模型(Message Model) 关键组件Broker消息存储工作流程 名词解释 名称服务器(NameServer) 定义: 名称服务器

【Rust光年纪】Rust 机器人学库全景:功能、安装与API概览

机器人学+Rust语言=无限可能:六款库带你开启创新之旅! 前言 随着机器人技术的快速发展,对于机器人学领域的高效、可靠的编程语言和库的需求也日益增加。本文将探讨一些用于 Rust 语言的机器人学库,以及它们的核心功能、使用场景、安装配置和 API 概览,旨在为机器人学爱好者和开发人员提供参考和指导。 欢迎订阅专栏:Rust光年纪 文章目录 机器人学+Rust语言=无限可能:

第二十二章 rust数据库使用:sea-orm详解

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust数据库使用:sea-orm详解 目录 注意一、前言二、项目管理三、迁移文件四、实体文件五、业务使用 一、前言 只要开发稍微大型一点的项目,数据库都是离不开的。 rust目前并没有特别成熟的数据库框架,sea-orm这个框架是我目前所看到的成熟度最高的一个,并且仍在积极开发中。 所以本文将以sea-orm框

Rust使用之【宏】

一、简单使用clap clap = { version = "4.5.17", features = ["derive"] } 其中,什么是features = ["derive"]:表示你希望在添加 clap 依赖时启用 derive 特性。这通常意味着你希望使用 clap 的派生(derive)宏功能,这些功能可以简化创建命令行接口的代码。例如,derive 特性可以让你使用 #[der

第二十一章 rust与动静态库的结合使用

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust与动静态库的结合使用 目录 注意一、前言二、库生成三、库使用四、总结 一、前言 rust中多了很多类型的库,比如前面章节中我们提到基本的bin与lib这两种crate类型库。 如果你在命令行执行下列语句: rustc --help 那么你将能找到这样的内容: --crate-type [bin|li