Rust 中的String与所有权机制

文章目录

  • 一、string
  • 二、所有权
    • 2.1 所有权与作用域
    • 2.2 对所有权的操作
      • 2.2.1 转移
      • 2.2.3 拷贝
      • 2.2.3 传递
    • 2.3 引用
      • 2.3.1 借用
      • 2.3.2 可变引用

一、string

之前学习过 Rust 只有几种基础的数据类型,但是没有常用的字符串也就是String,今天来学习一下 String;
Rust 中 String 是标准库的一部分,也就是 std::String , 但是这个 String 与其他语言中的 String 稍有不同,比如:
在这里插入图片描述

可以看到,当我想要以一种为指定字符串类型的方式定义了一字符串变量时,编译器自动显示出的类型是 &srr 而非 String, 而我指定了 String 类型后仍然有错;而从编译器给出的提示不难看出,“hello” 这样定义得到的是一个 “&str” 类型的值而非是个字符串,那么我们先假定这是一种未知的类型,后续再处理它,先去想办法定义出我们的字符串,打开官方文档: https://doc.rust-lang.org/std/string/struct.String.html

可以看到官方文档第一个示例告诉我们要像这样创建字符串:
在这里插入图片描述

但是官方没说为什么要这样定义,幸好 Rust 的源码是可以点进去的, 从 String::from 向里一步步执行:
在这里插入图片描述

from 执行的操作只有一个就是调用 to_owned 函数,但是需要注意,这里传进来的参数类型仍然是"&str"; 然后 to_owned 下一步是调用 as_bytes().to_owned() ,最后这个 to_owned() 则是调用了 to_vec ;
那么至此也就明白了,对于这一行代码:

    let hello = String::from("Hello, ");

我们传入的 “Hello,” 这会被编译器认为是一个字符数组,也就是一个字符串常量,即无法对其造成改变的一个对象;但是我们需要的是一个可变的字符串而非一组固定的字符,因此编译器将这个字符数组扩展为了一个 vector , 也就变成了一个可变的字符数组,也就是我最终想要的字符串;

其实这和C++差不多,只不过C++string底层应该直接是个指针而不是个vector

这样一来 “&str” 也就理解了,就是一个常量字符数组,所以是不可变的。在官方文档搜一下,果然也有,并且还有个好听的名字,字符串切片(string slice),具体参考: https://doc.rust-lang.org/std/primitive.str.html

官方文档中还介绍了两种类型的互转方法:
在这里插入图片描述

剩下的使用就是这两种类型自带的一些接口了,具体请参阅官方文档,这里不再细述;

二、所有权

2.1 所有权与作用域

很多小伙伴开始学习 Rust 是因为听说这是一种比C++更安全的语言,所以来了解一下,那么它安全在哪里?就安全在所有权机制,不再需要开发者像C++一样的去人工管理内存。

首先,所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时有规律地寻找不再使用的内存,比如Java;另一些语言中,程序员必须亲自分配和释放内存,比如C/C++。Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。所有权有以下规则:

* Rust 中的每一个值都有一个 所有者(owner)。
* 值在任一时刻有且只有一个所有者。
* 当所有者(变量)离开作用域,这个值将被丢弃。

举个例子,有以下一段代码:

fn main() {let s1 = "hello";{                let s = "hello s"; }  let s2 = "hello";
}

在上面的代码中, s 被一个括号圈住了,那么在这个括号里"hello s" 的所有者就是 s,而 s 的生命周期也只在括号范围内,也就是 s1 出现时 s 未出现, s2 出现时 s 已经死去。

有过C++ 经验的小伙伴看到这肯定很熟悉,这不就是 RAII 吗,或者说 Rust 中的每个变量都是个智能指针。

2.2 对所有权的操作

2.2.1 转移

刚刚说到这种所有权机制与C++的 RAII 很像,变量也和智能指针很像,那么是不是就和智能指针一样呢,测试一下:
在这里插入图片描述

图上可以看到,先定义了 s1 ,然后定义 s2 ,然后将 s1 传递给 s2 ,此时再使用 s1 会报错,提醒你s1 的值已经被转移出去了, 这时 s1 就已经被清空了。因为 Rust 变量离开作用域时会回收,所以如果这里不清空,在程序结束时s1 s2都会被回收,那么一块内存就会回收了两次,因此 Rust 的机制中 = 操作是转移而非拷贝。

看到这里,还是觉得是智能指针,只不过是unique_ptr,QAQ

2.2.3 拷贝

= 是转移而不是拷贝,那么想要使用拷贝该怎么写呢?比如字符串这样:
在这里插入图片描述

调用 clone 函数就行了。

然后有一个很有意思的事情,比如:
在这里插入图片描述

i32 类型变量不需要使用 clone 之类的函数,= 居然就是拷贝而不是转移;
官方给出的解释是 “像整型这样的在编译时已知大小的类型被整个存储在栈上,所以拷贝其实际的值是快速的。这意味着没有理由在创建变量 y 后使 x 无效。” 恕我直言,这不就是Rust中所有用到堆的变量就用的是智能指针吗。。。。。当然也可能是我理解不够深,反正我目前为止的感受就是这样。。。。

2.2.3 传递

之前提到过 “值在任一时刻有且只有一个所有者” ,那么如果将值传递给函数会怎么样呢:
在这里插入图片描述

很明显,作为参数传递给函数之后就失去了所有权;
但这样会带来一个问题,这个值如果不只一个函数再用后续怎么办?用函数返回值返回!
但是如果参数不只有一个呢?为每个函数的返回值都定一个结构体?
这样太麻烦了,万幸的是 Rust 提供了 引用。

2.3 引用

2.3.1 借用

官方说明中“引用(reference)像一个指针,因为它是一个地址,我们可以由此访问储存于该地址的属于其他变量的数据。 与指针不同,引用确保指向某个特定类型的有效值。”
很好理解,改一下刚才的代码:
在这里插入图片描述

可以用了,修改就是函数声明参数时加了一个&,传参时也加了一个&;

变量 str 有效的作用域与函数参数的作用域一样,不过当 str 停止使用时并不丢弃引用指向的数据,因为 str 并没有所有权。当函数使用引用而不是实际值作为参数,无需返回值来交还所有权,因为就不曾拥有所有权。

Rust 将创建一个引用的行为称为 借用(borrowing)。正如现实生活中,如果一个人拥有某样东西,你可以从他那里借来。当你使用完毕,必须还回去,并不拥有它,因此借用的值无法修改。
在这里插入图片描述

2.3.2 可变引用

正如不可变变量与可变变量一样,引用也可以变为可变引用,加个 mut 关键试试:
在这里插入图片描述

当然,像这段代码所写的,想要成为可变引用的前提是自身就是可变的。
另外,由于 Rust 的三条基础规则之“值在任一时刻有且只有一个所有者”,那么对于一个可变变量在同一个时刻也就不可以有多个引用;换个角度理解比如用一个 s1 作为 s 的可变引用后,那么 s 将不再可用,也自然不能再对一个无法使用的变量创建引用,如果这样使用编译器就会报错:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt中QFile、QByteArray QDataStream和QTextStream区别及示例

在Qt中,QFile、QByteArray、QDataStream和QTextStream是常用的文件和数据处理类。 主要功能和区别 QFile: QFile是用于读写文本和二进制文件以及资源的I/O设备。可以单独使用QFile,或者更方便地与QTextStream或QDataStream一起使用。 通常在…

紫光同创FPGA实现PCIE测速试验,提供PDS工程和Linux QT上位机源码和技术支持

目录 1、前言免责声明 2、我已有的PCIE方案3、设计思路框架PCIE硬件设计PCIE IP核添加和配置驱动文件和驱动安装QT上位机和源码 4、PDS工程详解5、上板调试验证并演示6、福利:工程代码的获取 紫光同创FPGA实现PCIE测速试验,提供PDS工程和Linux QT上位机源…

机器学习(新手入门)-线性回归 #房价预测

题目:给定数据集dataSet,每一行代表一组数据记录,每组数据记录中,第一个值为房屋面积(单位:平方英尺),第二个值为房屋中的房间数,第三个值为房价(单位:千美元…

笔记39:在Pycharm中为项目添加新解释器

很久不用pycharm都生疏了 a a a 第一步:创建虚拟环境 略 a a a 第二步:将虚拟环境应用到项目中去 【File】----【Settings】----【Project:~~~】-----【Project Interpreter】----【选择合适的解释器】 ​​​​​​​ 因为我们要用新的解释…

浅析 C# Console 控制台为什么也会卡死

一:背景 1. 讲故事 在分析旅程中,总会有几例控制台的意外卡死导致的生产事故,有经验的朋友都知道,控制台卡死一般是动了 快速编辑窗口 的缘故,截图如下: 虽然知道缘由,但一直没有时间探究底层…

SpringBoot2.x简单集成Flowable

环境和版本 window10 java1.8 mysql8 flowable6 springboot 2.7.6 配置 使用IDEA创建一个SpringBoot项目 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.…

网络协议--IP选路

9.1 引言 选路是IP最重要的功能之一。图9-1是IP层处理过程的简单流程。需要进行选路的数据报可以由本地主机产生&#xff0c;也可以由其他主机产生。在后一种情况下&#xff0c;主机必须配置成一个路由器&#xff0c;否则通过网络接口接收到的数据报&#xff0c;如果目的地址不…

原型与原型链

一、原型&#xff1a;prototype 1.什么是原型&#xff1f; javascript常被描述为一种基于原型的语言&#xff08;每个对象都拥有一个原型对象&#xff09; 当访问一个对象的属性时&#xff0c;它不仅在该对象上寻找&#xff0c;还会寻找该对象的原型&#xff0c;以及该对象原…

Git学习笔记——超详细

Git笔记 安装git&#xff1a; apt install git 创建版本库&#xff1a; git init 添加文件到版本库&#xff1a; git add 文件 提交文件到仓库&#xff1a; git commit -m “注释” 查看仓库当前的状态信息&#xff1a; git status 查看修改内容和之前版本的区别&am…

阿里云服务器x86计算架构ECS实例规格汇总

阿里云企业级服务器基于X86架构的实例规格&#xff0c;每一个vCPU都对应一个处理器核心的超线程&#xff0c;基于ARM架构的实例规格&#xff0c;每一个vCPU都对应一个处理器的物理核心&#xff0c;具有性能稳定且资源独享的特点。阿里云服务器网aliyunfuwuqi.com分享阿里云企业…

STM32 HAL高级定时器正交编码模式案例

STM32 HAL高级定时器正交编码模式案例 &#x1f516;基于stm32F030RBT6单片机采用高级定时器1&#xff0c;编码器模式&#xff0c;测试EC11编码器。 &#x1f3ac;EC11测试效果&#xff1a; &#x1f33f;STM32定时器编码器有3种映射模式: ✨本次采用的是上面的模式3&#x…

【网络】HTTPS讲解(侧重于加密、秘钥、证书的讲解)

HTTPS讲解 前言正式开始安全HTTP和HTTPS的关系什么是加密和解密为什么要加密运营商劫持中间人 常⻅的加密⽅式对称加密⾮对称加密 数据摘要数字签名HTTPS 的⼯作过程⽅案 1 - 只使⽤对称加密&#xff08;不可靠&#xff09;⽅案 2 - 只使⽤⾮对称加密&#xff08;不可靠&#x…

Node编写用户登录接口

目录 前言 服务器 编写登录接口API 使用sql语句查询数据库中是否有该用户 判断密码是否正确 生成JWT的Token字符串 配置解析token的中间件 配置捕获错误中间件 完整的登录接口代码 前言 本文介绍如何使用node编写登录接口以及解密生成token&#xff0c;如何编写注册接…

【Qt】消息机制和事件

文章目录 事件event()事件过滤器案例&#xff1a;检测鼠标事件案例&#xff1a;定时器 事件 事件&#xff08;event&#xff09;是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口需要重新绘制的时候&#xff0c;都会发出一个相应的事…

Docker Swarm 集群搭建

Docker Swarm Mode Docker Swarm 集群搭建 Docker Swarm 节点维护 Docker Service 创建 1.准备主机 搭建一个 docker swarm 集群&#xff0c;包含 5 个 swarm 节点。这 5 个 swarm 节点的 IP 与暂 时的角色分配如下&#xff08;注意&#xff0c;搭建完成后会切换角色&#xff…

Linux绝对路径和相对路径

在 Linux 中&#xff0c;简单的理解一个文件的路径&#xff0c;指的就是该文件存放的位置。 只要我们告诉 Linux 系统某个文件存放的准确位置&#xff0c;那么它就可以找到这个文件。指明一个文件存放的位置&#xff0c;有 2 种方法&#xff0c;分别是使用绝对路径和相对路径。…

​​​​​​​Python---练习:打印直角三角形(利用wihle循环嵌套)

案例&#xff1a; 打印直角三角形&#xff0c;特征&#xff1a;一共有5行&#xff0c;第1行&#xff0c;有1列。第2行&#xff0c;有2列&#xff0c;第3&#xff0c;有3列。 思考&#xff1a; pycharm里面&#xff0c;输出三角形&#xff0c;因为本来控制台就是长方形&#…

Python桌面应用之XX学院水卡报表查询系统(Tkinter+cx_Oracle)

一、功能样式 Python桌面应用之XX学院水卡报表查询系统功能&#xff1a; 连接Oracle数据库&#xff0c;查询XX学院水卡操作总明细报表&#xff0c;汇总数据报表&#xff0c;个人明细报表&#xff0c;进行预览并且支持导出报表 1.总明细报表样式 2.汇总明细样式 3.个人明细…

硬件信息查看工具 EtreCheckpro mac中文版功能介绍

etrecheckpro mac中文版是一款专业的硬件信息查看工具&#xff0c;它能够快速的检测Mac电脑的软硬件信息&#xff0c;加强用户对自己计算机的了解&#xff0c;EtreCheckPro for Mac下载首先会对电脑的软硬件信息进行扫描收集&#xff0c;之后才会显示出来。EtreCheck Mac版报告…

Python深度学习进阶与应用丨注意力(Attention)机制、Transformer模型、生成式模型、目标检测算法、图神经网络、强化学习详解等

目录 第一章 注意力&#xff08;Attention&#xff09;机制详解 第二章 Transformer模型详解 第三章 生成式模型详解 第四章 目标检测算法详解 第五章 图神经网络详解 第六章 强化学习详解 第七章 深度学习模型可解释性与可视化方法详解 更多应用 近年来&#xff0c;伴…