Rust 基础再理解
Rust堆栈
Rust中各种类型的值默认都存储在栈中,除非显式地使用Box::new()
将它们存放在堆上,但数据要存放在栈中,要求其数据类型的大小已知。对于静态大小的类型,可直接存储在栈上,如裸指针、布尔、字符、整数浮点数,数组等。
动态大小的(Vec
、string
)都是存堆的
一些注意事项
- 栈中的数据赋值给变量的时候,数据是直接放在栈中的。
- 类型的值都默认放在栈中,所以创建引用的时候,引用的是栈里的值。
- 容器中保存的是原始类型的栈里的值或者指向堆数据的引用
- 字符串字面量,
static
静态变量都会硬编码嵌入到二进制程序的全局内存区 const
定义的常量,会在编译期间直接以硬编码的方式内联插入到使用常量的地方,即,直接硬编码到对应代码行。同时函数也可以内联,即函数对应代码体会直接展开并插入到调用函数的地方,省去调用函数的开销。
位置与值
位置:某一块内存位置,它有自己的地址,有自己的空间,有自己所保存的值。
值:存储到位置中的数据(即保存在内存中的数据)
位置的产生
- 会产生变量的时候(初始化)
- 需要保存某个值的时候(函数调用参数和返回值)
- 产生新的值(引用,解引用)
let 语句
let a = 1;
a
:为变量名,也是对内存位置的一个可读代号,编译期间会被替换为更低级的代号或者直接为地址。也就是位置,是存值1
的一块内存。
每个位置就是它所放值的所有值,因为每个值都只能存放在一个位置中,所以每个值都只能有一个所有者。let v = vec![1, 2, 3, 4];
v
:位置,代表栈中的一块内存,值是一个指针地址,实际数据是放在堆里的。
引用
Rust的引用是一种原始数据类型,位置仍然是栈里,保存的值和指针一样,是一个地址。该地址指向了**位置(**也就是前面的a
和v
)
如
let n = 33; // 假设n的地址为0x234
let nn = &n; // 假设nn的地址为0x123
那么,nn
的位置是0x123
,它存的值是0x234
,也就是n
的地址。
编译器维护栈内存,所以它知道栈中的某个内存是否安全,而堆内存由程序员自己负责,程序员自己的行为是无法保证安全的。
所以,Rust的行为模式是将是涉及到内存安全的概念扔到栈上,让程序员远离对堆的操作。所以,允许允许对栈中同一个数据的多个指向,不允许对堆中同一个内存的多个指向,即变量存在多个引用,但所有权只能有一个。
位置的属性
位置的属性和状态都由编译器在编译期进行维护。
位置有类型,有标记(是否被引用,可变引用还是不可变,共享还是独占等等),根据位置的类型是否实现Copy Trait
来决定该位置的是拷贝还是移走。
所有权和借用
变量作用域
我们知道rust 变量在脱离作用域之后就会被销毁,但事实是,变量在跳出作用域时,会自动Drop Trait
的drop
函数来销毁内存中堆和栈的数据,全局内存中的数据是从程序启动到终止期间一直存在。
另外rust的作用域为一对大括号{}
,大括号的作用域是可以访问大括号外部的变量,而在函数的作用域内则不行,这被称为捕获环境,函数是不能捕获环境的,而大括号可以捕获环境。
数据的拷贝
由于所有权问题和变量脱离作用域而引起的内存二次释放问题,rust是不允许有两个指针同时指向同一块内存的。所以rust 没有浅拷贝和深拷贝的概念,取而代之的是move
、copy
和clone
。
move
:也就是转移所有权,涉及到的过程是拷贝到目标变量,同时会将原来的变量设置到未初始的状态。rust 默认使用的就是move
。
当使用值的时候,就会产生位置,那么就会发生移动。解引用,字段访问,索引访问等都会隐式移动。
copy
:和move
的区别就是,拷贝之后原来的变量还是可以用。如果要使用copy
,就需要要拷贝的数据类型实现了Copy Trait
,手动实现的时候需要同时实现Clone Trait
。clone
:clone
和copy
很接近,区别在于,- Copy时,只拷贝变量本身的值,如果这个变量指向了其它数据,则不会拷贝其指向的数据。
- Clone时,拷贝变量本身的值,如果这个变量指向了其它数据,则也会拷贝其指向的数据。
函数调用之后也是会转移所有权的,有时候这样是很不方便的,所以在传参的时候可以传递到变量的引用,引用时保存在栈里,也实现了Copy Trait
,这样效率会更高。
可变引用的排他性
不可变引用是可以共存的,但是可变引用具有排他性,在同一作用域同一数据只能有一个。
这里的排他性,应该看作一把独占锁,在当前作用域内,从第一次使用可变引用开始创建这把独占锁,之后无论使用原始变量(即所有权拥有者)、可变引用还是不可变引用都会抢占这把独占锁,以保证只有一方可以访问数据,每次抢得独占锁后,都会将之前所有引用变量给锁住,使它们变成不可用状态。当离开当前作用域时,当前作用域内的所有独占锁都被释放。
回顾一下可变引用的几个性质
- 同一作用域,特定数据只能有一个可变引用
- 可变借用不能用于不可变借用上
- 有了可变借用就不能再有不可变借用
- 引用作用域和变量作用域不一样,它的结束位置再最后一次使用的位置
自从第一次使用可变引用导致独占锁出现后,可以随时使用原始变量、可变引用或不可变引用来抢独占锁,但抢锁后以前的引用变量就不能再用,且当前持有的锁也可以随时被抢走。不可变引用抢占之后所有的包括自身都是不可用的,但再次使用可变引用抢占锁之后,该可变引用是可用的。
一切都由程序员控制,程序员可以在任意代码位置通过原始变量或引用来抢锁。
模式匹配
rust中可分为
- 不可反驳的模式(irrefutable):一定会匹配成功,否则编译错误,如
let
赋值,for
迭代,函数传参等。 - 可反驳的的模式(refutable):可以匹配成功,也可以匹配失败,匹配失败的结果是不执行对应分支的代码,如
if let
和while let
match
匹配支持两个模式
- 当明确给出分支的Pattern时,必须是可反驳模式,这些模式允许匹配失败
- 使用
_
作为最后一个分支时,是不可反驳模式,它一定会匹配成功 - 如果只有一个Pattern分支,则可以是不可反驳模式,也可以是可反驳模式
再谈Trait
组合
Trait
最基本的作用是从多种类型中抽取出共性的属性或方法,主要表现为泛型数据类型。可以理解为,它描述了一种通用的功能,功能都要求具有某些特殊的行为,同时功能可以被很多种类型实现。
同样,一个类型也可以实现很多种Trait
,组合出很多功能,这和一般面向对象编程语言的继承有所不同,不用继承冗余的功能,而更加的自由。
组合和继承的关系可以理解为 **has a **和 is a 的关系。
特征对象
也就是具有某个特征功能的类的实例。
上篇提到过,Duck Typing ,也就是只需要叫起来想鸭子,就可以当成鸭子来使用。(只需要你会打螺丝,不管你是不是大学生。)
这里的意思就是,实现了某个特征的众多对象都具有该功能,而由于 Trait
自身不能当作数据类型来用(因为,可能一种类型实现了很多中 Trait
,显然无法用一种 Trait
来代替这种数据类型)。因此就诞生了 Trait Object
,也就是将实现了 Trait A
的类型 B,C,D 当作 Trait A
的 Trait Object
使用。(可以类比为继承里的父类)
Trait object
的创建是通过&dyn T
或者指针Box<dyn T>
,Rc<dyn T>
等等
本质就是由于 Trait object
的大小是不定的,所以选择将引用存在栈中,包含两部分数据
- 指向数据的指针:指向实现了
Trait
的具体类型的实例, - 指向一个虚表 vtable 的指针:因为实现了
Trait
的类型有很多,而每个类型拥有的方法时各不相同的,所以需要一个虚表来区分保存。虚表中保存了实例可以调用的,实现的来自特征Trait
的方法。当该对象调用方法时,直接从虚表中找到方法,然后调用。
其他
Struct
和Enum
类型需要手动实现Trait
,即,使用#[derive()]
- 特征是支持继承的,如
trait B{}
trait A: B{}
当类型想实现 Trait A
的时候,需要要求同时实现 Trait B
参考
Rust入门秘籍
相关文章:
Rust 基础再理解
Rust堆栈 Rust中各种类型的值默认都存储在栈中,除非显式地使用Box::new()将它们存放在堆上,但数据要存放在栈中,要求其数据类型的大小已知。对于静态大小的类型,可直接存储在栈上,如裸指针、布尔、字符、整数浮点数&a…...

Opencv cuda版本在ubuntu22.04中安装办法,解决Could NOT find CUDNN的办法
文章目录 概要下载cuda的runfile版本配置环境变量官网下载cudann安装Opencv依赖包下载opencv和opencv_contrib并解压准备编译安装anaconda环境执行编译命令安装OpenCV并检查是否安装成功 概要 解决以下安装问题: -- Could NOT find CUDNN: Found unsuitable versi…...
全网首发YOLOv8暴力涨点:Gold-YOLO,遥遥领先,超越所有YOLO | 华为诺亚NeurIPS23
💡💡💡本文独家改进:提出了全新的信息聚集-分发(Gather-and-Distribute Mechanism)GD机制,Gold-YOLO,替换yolov8 head部分 实现暴力涨点 Gold-YOLO | 亲测在多个数据集能够实现大幅涨点 💡💡💡Yolov8魔术师,独家首发创新(原创),适用于Yolov5、Yolov7、…...
BD就业复习第四天
1. 布隆过滤器怎么实现去重 布隆过滤器是一种用于快速检查一个元素是否可能存在于一个大集合中的数据结构,但它并不适用于精确去重。因为布隆过滤器具有一定的误判率(可能会将不存在的元素误判为存在),所以不能确保完全的去重。但…...

数据结构 | 树
树 树是n(n>0)个结点的有限集。当n 0时,称为空树。在任意一棵非空树中应满足: 有且仅有一个特定的称为根的结点。当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm&#…...

Android11 适配
一、修改targetSdkVersion为30 将build.gradle的目标版本targetSdkVersion修改为30(Android 11) targetSdkVersion 30Android11的改变改变主要影响以Adnroid11 为目标版本的应用(targetSdkVersion>30才有影响),和所…...

UML基础与应用之对象图
什么是对象图? 对象图表示一组对象及它们之间的关系,是某一时刻系统详细信息的快照,描述系统交互的静态图形,它由协作的对象组成,但不包含在对象之间传递的任何消息。因为对象是类的实例化,所以说某一时刻…...

英码科技精彩亮相火爆的IOTE 2023,多面赋能AIoT产业发展!
9月20日至22日,在这金秋飒爽的季节,为期三天的IOTE 2023第二十届国际物联网展深圳站在深圳国际会展中心盛大举行。英码科技精彩亮相本届展会,并在同期举办的AIoT视觉物联产业生态大会发表了主题演讲,与生态伙伴们共同探讨AIoT产业…...

400G QSFP-DD FR4 与 400G QSFP-DD FR8光模块:哪个更适合您的网络需求?
QSFP-DD 光模块随着光通信市场规模的不断增长已成为400G市场中客户需求量最高的产品。其中400G QSFP-DD FR4和400G QSFP-DD FR8光模块都是针对波分中距离传输(2km)的解决方案,它们之间有什么不同?应该如何选择应用?飞速…...

【Android】Kotlin 中的 apply、let、with、also、run 到底有啥区别?
一、图示 二、apply apply 函数接收一个对象并返回该对象本身。它允许您在对象上执行一些操作,同时仍然返回原始对象。 这个函数的语法为: fun <T> T.apply(block: T.() -> Unit): T 其中,T 是对象的类型,block 是一…...
设计模式——职责链模式
职责链模式 职责链模式职责链模式解决什么问题?职责链模式实现 职责链模式 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象练成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止 …...
小程序自定义tabbar,中间凸起
微信小程序自带tabbar,但无法实现中间按钮凸起样式和功能,因此按照设计重新自定义一个tabbar 1、创建tabbar文件,与pages同级创建一个文件夹,custom-tab-bar,里面按照设计图将底部tabbar样式编写 <view class"tab-bar&q…...
数据结构-顺序栈C++示例
栈(stack)是限定仅在表尾进行插入或删除操作的线性表。 对栈来说,表尾端称为栈顶(top), 表头端称为栈底(bottom),不含元素的空表称为空栈。 假设栈 S ( a 1 , a 2 , a 3 , ⋯ , a n ) S(a_1,a_2,a_3,\cdots,a_n) S(a1,a2,a3,⋯,an…...

若依cloud -【 100 ~ 103 】
100 分布式日志介绍 | RuoYi 分布式日志就相当于把日志存储在不同的设备上面。比如若依项目中有ruoyi-modules-file、ruoyi-modules-gen、ruoyi-modules-job、ruoyi-modules-system四个应用,每个应用都部署在单独的一台机器里边,应用对应的日志的也单独存…...

可转债实战与案例分析——成功的和失败的可转债投资案例、教训与经验分享
实战与案例分析——投资案例研究 股票量化程序化自动交易接口 一、成功的可转债投资案例 成功的可转债投资案例提供了有价值的经验教训,以下是一个典型的成功案例: 案例:投资者B的成功可转债投资 投资者B是一位懂得风险管理的投资者&#…...

@NotNull注解不生效,全局异常处理
1.引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>3.1.2</version> </dependency> 2:实体类 实体类属性加上NotNull注解…...

【办公自动化】使用Python一键往Word文档的表格中填写数据(文末送书)
🤵♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞Ǵ…...

OpenHarmony应用核心技术理念与需求机遇简析
一、核心技术理念 图片来源:OpenHarmony官方网站 二、需求机遇简析 新的万物互联智能世界代表着新规则、新赛道、新切入点、新财富机会;各WEB网站、客户端( 苹果APP、安卓APK)、微信小程序等上的组织、企业、商户等;OpenHarmony既是一次机遇、同时又是一次大的挑战&…...

让Pegasus天马座开发板实现超声波测距
在完成《让Pegasus天马座开发板用上OLED屏》后,我觉得可以把超声波测距功能也在Pegasus天马座开发板上实现。于是在箱子里找到了,Grove - Ultrasonic Ranger 这一超声波测传感器。 官方地址: https://wiki.seeedstudio.com/Grove-Ultrasonic_Ranger 超声…...
C++11 多线程学习
C11学习 一、多线程 1、模板线程是以右值传递的 template <class Fn, class... Args> explicit thread(Fn&& fn, Args&&... args)则需要使用到std::ref和std::cref很好地解决了这个问题,std::ref 可以包装按引用传递的值。 std::cref 可以…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...

小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...