研读Rust圣经解析——Rust learn-5(所有权,强大的String)

news2025/1/19 17:21:30

研读Rust圣经解析——Rust learn-5(所有权,强大的String)

  • 所有权
    • 栈和堆
      • 相同点
    • 所有权规则
      • 作用域
  • String
    • String
      • 创建String
        • 创建空字符串
        • 从字符串字面量创建(将&str转化为String)
    • str
      • 特点
      • 创建str
  • 所有权转移
    • String源码
  • 深克隆
    • clone方法
  • 作用域消费(所有权转移-续)

所有权

Rust 的核心功能(之一)是 所有权(ownership),Rust 通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。

栈和堆

这两个概念可以说是非常经典,在Rust中我们应该比其他语言考虑和理解这两个概念更多

相同点

栈和堆都是代码在运行时可供使用的内存

  1. 栈中的所有数据都必须占用已知且固定的大小
  2. 后进先出
  3. 存储速度块

  1. 存储在编译时大小未知或大小可能变化的数据
  2. 存储时会需求一块尽可能大的内存区域
  3. 指针指向,访问慢

所有权规则

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

请大家牢牢记住这三大规则,因为如果你刚接触Rust不久,你很容易犯所有权的错误!特别是最后一条

作用域

作用域是一块区域,当变量在自己所属的作用域中变量是有效的,出了则变量被释放
我们来看看这个例子:

fn scope_area() -> &str {
    let a ="5";
    return a;
}

fn main() {
    let x = scope_area();
    println!("{}", x);
}

这段代码在scope_area方法中声明了一个a变量,然后将其返回,注意了,这里我们返回的是&str类型,简单来说它是字符串切片,是对字符串的借用,这段代码看似编辑器通过了,没有语法错误,实则:

在这里插入图片描述
出现如上的错误,说这个需要一个生命周期标识,我们来说一下为什么?
首先&str不是String!而是对String的借用,是字符串切片,他只是借了String,不是它本身,就好比,别人借用了你的一支笔,他就不能说这支笔是他的,他没有处理这只笔的权限,所以他不能再把你的笔借给其他人。
那么&str也是这样,他也无法把所有权移交给其他变量,所以一出作用域,他就失效了,被释放了,新的变量自然无法获取到返回值。当然这里编译器告诉了你解决的方法,就是使用生命周期,但是现在我们没学到,所以不予采纳。
正确方式应该是:

fn scope_area() -> String {
    let a = "5";
    return a.to_string();
}

fn main() {
    let x = scope_area();
    println!("{}", x);
}

这里我们最后通过to_string将字符串切片转化为了String,自然没有这个问题了
另一种:

fn scope_area() -> String {
    let a = "5";
    return a.to_owned();
}

fn main() {
    let x = scope_area();
    println!("{}", x);
}

我们通过to_owned方法获取到了a真实字符串的所有权,此时相当于别人说我把笔送你了,你就有了笔的所有权,你这时候就可以处理这只笔了,你再把笔怎么样都是你的事情。

String

String but not only String,这是我认为对Rust中的String最准确的一句话,因为Rust中String不是简单的一个char数组,它有很多花样,以至于我看来,如果你弄懂了Rust的String你就掌握了类型精髓的三分之一(可能大家觉得三分之一很少,但是真正了解后你会知道这是很多的内容),接下来我会详细的解析’String’类型

String

UTF-8编码的可增长字符串。 字符串类型是对字符串内容拥有所有权的最常见的字符串类型。它与借用的对应物原始str有着密切的关系。String是存在堆上的

创建String

创建空字符串

let x = String::new();

从字符串字面量创建(将&str转化为String)

let a = String::from("test");

str

称为“字符串切片”,是最原始的字符串 类型。它通常以其借来的形式出现,&str

特点

  1. 不可变
  2. 在编译时知道内容
  3. 直接以硬编码写入可执行文件
  4. 快速高效

创建str

按照如下写法,直接创建就是一个&str,

let a = "test";

出了上方的String|str实际上Rust中还有很多类型的String,如OsString

所有权转移

这个名字只是我这样叫而已
我们来说明一下为什么我这样说,首先我们要清楚一个概念,在Rust中String也是复合类型不是简单类型,简单类型指的是那些没有容量一经声明值就能确定的,即:i8,u8,i32,f64,bool等这些在前面介绍到的,而String实则是一个Vector!

String源码

以下是String的源码:

#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), lang = "String")]
pub struct String {
    vec: Vec<u8>,
}

我们看到实则String是Vec<u8>至于为什么是u8,大家应该知道u8是无符号整数,范围0~255,这个就是我们常说的ASCLL码的有效范围

所以我们要明确一个概念,String是复合类型,有长度有容量,可以扩容,存在堆中,他的引用也就是指针在栈中!

所以当我们使用如下的代码时会出现问题:

fn main() {
    let a = String::from("test");
    let b = a;
    println!("{}", b);
    println!("{}", a);
}

在这里插入图片描述
从错误中我们看到 value borrowed here after move借用的值在移动后,也就是说所属于a的值被移动了,移动到了b,此时b抢占了a的String的所有权,致使a的值失效了!
我们一样举例子理解一下:首先a有一支笔,a把笔送给了b,此时b拥有了笔的所有权,a已经没有笔了,所以再去问a借笔的时候,就出现了错误
这就是所有权转移产生的问题
那么如何解决这个问题呢?

深克隆

为了解决所有权转移的问题,我们用到了深克隆,我们复制出一份一摸一样的数据,这样两个变量都会有值,就不存在所有权转移的问题

clone方法

通过使用clone方法直接就能克隆一份一样的数据,注意前提是实现了Clone的trait!当然这里你不知道什么是trait,如果你有其他语言的基础,那就理解为接口,或者你理解为一个规则,实现了规则就相当于有了一个入场的门票,就可以进出了

fn main() {
    let a = String::from("test");
    let b = a.clone();
    println!("{}", b);
    println!("{}", a);
}

如果你自己写了一个结构体,也想要clone一下有没有办法呢?其实这很简单,就是实现一下Clone,但实际上我们不会这样干,因为这是耗费时间耗费精力的,Rust提供了一个#[derive(Clone)]标注以帮助开发人员直接实现clone

#[derive(Clone)]
struct test{
	//..
}

作用域消费(所有权转移-续)

我们先来看一份代码

fn scope_area(mut b: String) -> String {
    b.push_str("hello");
    return b;
}


fn main() {
    let mut a = String::from("test");
    scope_area(a);
    println!("{}", a);
}

看上去好像没啥问题,但是编译后,会告诉你:
在这里插入图片描述
出现了和前面我们在如下代码里一样的问题

fn main() {
    let a = String::from("test");
    let b = a;
    println!("{}", b);
    println!("{}", a);
}

这说明了两者的本质问题一样,都是所有权转移了
接下来我们来理解一下,有个a是String,有个函数将a作为参数传入,在进行一系列操作后函数执行结束,此时我们再去访问a的时候所属于a的值已经被函数抢占走了,a就没有值了,函数对a的值进行一些操作后函数结束,这时所属于a的值没有被还回来,而是被释放了,这就是原因

打个比方:你有500块钱,跑到一个娱乐场所消费了一圈,最终你把500块钱全部用完,店铺挣得了你的钱,钱就不是你的,这不就是前面的所有权转移吗!

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

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

相关文章

Matplotlib基本图形使用折线图-柱状图-散点图-饼图的完整代码含示例

目录 Matplotlib基本折线图的使用 1. 导入matplotlib库 2. 准备数据 3. 绘制折线图 4. 加上标签和标题 5. 自定义样式 6. 完整代码 ​编辑 绘制散点图 导入 matplotlib 库和 numpy 库 准备数据 绘制散点图 ​编辑 绘制饼图 导入 matplotlib 库和 numpy 库 准备数…

JS尺寸相关

文章目录元素偏移量 offset 系列offset 系列常用属性offset 与 style 区别获取鼠标在盒子内的坐标模态框放大镜效果元素client 系列元素client系列属性元素滚动 scroll 系列元素 scroll 系列属性页面被卷去的头部兼容性解决方案监听滚动效果仿淘宝固定侧边栏缓动动画筋斗云案例…

实战打靶集锦-015-djinn3

提示&#xff1a;本文记录了作者一次曲折的打靶提权经历 目录1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 Lighttpd探查4.1.1 浏览器探查4.1.2 EXP搜索4.1.2.1 CVE-2019-110724.1.2.2 CVE-2018-190524.2 Werkzeug探查4.2.1 浏览器探查4.2.2 EXP搜索4.2.2.1 目录遍历4.2.2…

Stable Diffusion Web UI + Anaconda环境 + 本地Windows系统部署

Stable Diffusion Web UI Anaconda环境 本地Windows系统部署 最近的很多AIGC模型层出不穷&#xff0c;Stable Diffusion 模型作为一个开源的热门生成式模型&#xff0c;或许对未来的各行各业都能产生深远的影响&#xff0c;了解这个模型并会使用可能是很多人目前想要学习的&…

车载Mini LED持续升温,各家厂商进展如何?

去年&#xff0c;Mini LED背光技术在车载显示赛道上初露头角&#xff0c;多款搭载 Mini LED 屏幕的汽车陆续发布。随着新能源车渗透率的提高&#xff0c;车载显示成为明确增长的赛道&#xff0c;为Mini LED背光进入车载带来利好。 结合今年各家厂商披露的信息来看&#xff0c…

浮点型数据在内存的存储方式

目录 大体规则 特殊规定 由于浮点型在内存中的存储方式相较于整型的要复杂一些&#xff0c;而且很容易忘掉&#xff0c;所以就将部分知识点整理了一下&#xff0c;写成一篇博客。 大体规则 根据国际标准&#xff08;电气和电子工程协会&#xff09;IEEE 754&#xff0c;任意…

【数据结构】- 初识数据结构之空间复杂度(下)

文章目录前言一、空间复杂度1.1空间复杂度简解1.2常见空间复杂度的计算举例二、常见复杂度的对比总结前言 将喜欢的一切留在身边 这便是努力的意义. 本章是关于初识数据结构之空间复杂度(下) 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、空间复…

真的干不过,00后整顿职场已经给我卷麻了,想离职了...

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&#x…

D. Li Hua and Tree(set操作)

Problem - D - Codeforces 李华有一个有n个顶点和n -1条边的树。树的根是顶点1。每个顶点i的重要性为a。将子树的大小表示为该子树中顶点的数量&#xff0c;将重要性表示为该子树中顶点的重要性之和。将非叶顶点的重子结点表示为具有最大子树大小的子结点。如果存在多个重子&am…

安全防御 --- 入侵检测 --- IDS、IPS

入侵检测 1、入侵检测经典理论 系统访问控制要针对三类用户 &#xff08;1&#xff09;合法用户 &#xff08;2&#xff09;伪装 --- 攻破[流程控制]&#xff08;超出了合法用户的行为范围&#xff09; 身份仿冒&#xff08;可能是最早提出不能仅依赖于身份认证&#xff0c;还…

STM32F4+FreeRTOS+LVGL实现嵌入式快速开发(缝合怪)

极速进行项目开发&#xff0c;只需要懂一款芯片架构一个操作系统一个GUI。各种部件程序全靠抄 &#xff0c;成为究极缝合怪。本文用stm32f407FreeRTOSlvgl演示一些demo。 原文链接&#xff1a;STM32F4FreeRTOSLVGL实现快速开发(缝合怪) lvgl官方的音乐播放器demo&#xff1a;…

微信小程序学习笔记

一、Node.js主题 1、npm&#xff1a;node.js包管理工具&#xff0c;有超过60万个JavaScript代码包可供下载 2、Node.js&#xff1a;运行在服务端的JavaScript&#xff0c;基于Chrome JavaScript建立的一个平台&#xff0c;基于Google V8引擎。 3、Nodejs安装教程&#xff1a…

Redis篇之主从复制及哨兵模式

主从复制及哨兵模式 1、概念 主从复制&#xff1a; 是指将一台 Redis 服务器的数据&#xff0c;复制到其他的 Redis 服务器。前者称为主节点&#xff08;Master/Leader&#xff09;,后者称为从节点&#xff08;Slave/Follower&#xff09;&#xff0c; 数据的复制是单向的&a…

毕业设计 基于51单片机的智能水表水流量计流量报警器温度设计

基于STM32的语音IC卡停车管理系统1、快速完成毕设的方法2、项目资料2.1 系统框架2.2 系统功能3、部分电路设计3.1 STC89C52单片机最小系统电路设计3.2 继电器控制电路设计3.3 DS18B20温度检测电路设计3.4 LCD1602液晶显示电路设计4、部分代码展示4.1 LCD1602液晶显示屏引脚初始…

2023年第十四届蓝桥杯 C++ B组参赛经验总结

没错&#xff0c;今年本菜狗又来啦~~ hhh &#xff0c; 文章当时比赛完就写完了&#xff0c; 发的有点晚 比赛成绩 &#xff08;等出来我就写这里&#xff09; 感觉最多省二 估计没省一了555 赛前准备 赛前把蓝桥杯课基本都刷了 &#xff0c; 但是还是感觉有点慌 刷题经验 …

【mysql是怎样运行的】-B+树索引深入理解

文章目录1. 无索引查找方式1.1 在一个页中查找1.2 在多个页中查找2. 索引3. 简易索引方案4. InnoDB 中的索引方案5. **常见索引概念**数据页与记录关系&#xff1a;各个数据页可以组成一个 双向链表&#xff0c;而每个数据页中的记录会按照主键值从小到大的顺序组成一个 单向链…

Linux主机上的用户信息传递(查询用户(w,who,last,lastlog),用户对谈(write,mesg,wall),用户邮箱mail)

文章目录Linux主机上的用户信息传递查询用户&#xff1a;w、who、last、lastlog用户对谈&#xff1a;write、mesg、wall用户邮箱&#xff1a;mail使用案例给自己的QQ邮箱发送一封邮件①获取授权码②使用mailx发送邮件③测试是否可以发送邮件Linux主机上的用户信息传递 想过吗如…

阿里版 ChatGPT 突然上线!

转自:纯洁的微笑 其实早本月初&#xff0c;就传出过不少阿里要推出类ChatGPT的消息。 前几天率先流出的天猫精灵“鸟鸟分鸟”脱口秀版GPT&#xff0c;就是基于大模型的“压缩版”&#xff0c;已经以其惊艳表现吸引了众目光。 如今“原版大菜”上桌&#xff0c;自然一点即着&a…

PHP反序列化魔术方法详细解析及实例公私有属性对比

目录 一、魔术方法利用点分析 <__construct&__destruct> <__toString> <__call> <__get> <__set> <__sleep> <__wakeup> <__isset> <__unset> <__invoke> <总结> 二、对象变量属性及序列化…

Pandas 常用按照查询条件筛选数据

文章目录1. 筛选指定的列2. 按照条件筛选3.1 单条件筛选3.2 多条件组合筛选创建一个DataFrame import pandas as pd data {name:[张三, 李四, 王五, 赵六],age:[20, 21, 22, 23], gender: [0, 1, 1, 1], stature: [165, 189, 178, 160], year: [2000, 2002, 2003, 1993]} df …