Rust 登堂 之 Sized和不定长类型 DST(七) - 实践

news/2025/9/23 12:54:02/文章来源:https://www.cnblogs.com/yfceshi/p/19106984

在Rust 中类型有多种抽象的分类方式,例如本书之前章节的: 基本类型,集合类型,复合类型等,再比如说,如果从编译器合适能获知类型大小的角度触发,可以分为两类

        定长类型 sized ,这些类型的大小在编译时是一直的。

        不定长类型 unsized ,与定长类型相反,它的大小只有到了程序运行时才能动态获知,这种类型又被称之为 DST

动态大小类型DST

读者大大们之前学过的几乎所有类型,都是固定大小的类型,包括集合 Vec ,String 和 HashMap 等,而动态大小类型刚好与之相反: 编译器无法在编译期得知该类型值的大小,只有到了程序运行时,才能动态获知,对于动态类型,我们使用 DST(dynamically sized types ) 或者 unsized 类型来称呼它。

上述的这些集合虽然底层数据可动态变化,感觉显示动态大小的类型,但是实际上,这些底层数据只是保存在堆上,在栈中还存有一个引用类型,该引用包含了集合的内存地址,元素数目,分配空间信息,通过这些信息,编译器对于该集合的实际大小了若指掌, 最最重要的是: 栈上的引用类型是固定大小的,因此它们依然是固定大小的类型。

正因为编译器无法在编译期获知类型大小,若你试图在代码中直接使用DST类型,将无法通过编译

现在给你一个挑战:  想出几个DST类型,俺厚黑地说一举,估计大部分人都想不出这样的类型,

试图创建动态大小的数组

fn my_function(n: usize) {
let array = [123;n];
}

以上代码就会报错(错误输出的捏融并不是因为 DST,但根本原因是类似的),因为 n 在编译器无法得知,而数组类型的一个组成部分就是长度,长度变为动态的,自然类型就变成了 unsized.

切片

切片也是一个典型的DST 类型,具体详情常见另一篇文章: 易混淆的切片和切片引用

str

考虑以下这个类型:str , 感觉有点眼生? 是的,它既不是 String 动态字符串,也不是 &str 字符串切片,而是一个 str ,它是一个动态类型,同时还是 String 和 &str 的底层数据类型,由于 str 是动态类型,因此它的大小直到运行期才知道,下面的代码会因此报错

// error
let s1: str = "Hello there!";
let s2: str = "How's it goring?";
// ok
let s3: &str = "on?"

Rust 需要明确地知道 一个特定类型的值占据了多少内存空间,同时该类型的所有值都必须使用相同 大小的内存,如果Rust 允许我们使用这种动态类型,那么这两个 str 值就需要占用同样大小的内存,这显然是不现实的 s1 占用了 12直接, s2 占用了 15字节 ,总不至于为了满足同样的内存大小,空白字符去填补字符串吗?

所以,我们只有一条路走,那就是给它们一个固定大小的类型 : &str, 那么为何字符串切片 &str 就是固定大小呢? 因为它的引用存储在栈上,具有固定大小(类似指针),同时它指向的数据存储在堆中,也是已知的大小,在加上 &str 引用中包含有堆上数据内存地址,长度等信息,因此最终可以得出字符串切片是固定大小类型的结论

与&str 类似, String 字符串也是固定大小的类型

正因为 &str 的引用有了底层堆数据的明确信息,它才是固定大小类型,假设如果它没有这些信息呢?那它也将编程一个动态类型,因此,将动态数据固定化的秘诀就是使用引用指向这些动态数据,然后在引用存储相关的内存位置,长度等信息

特征对象

fn foobar_1(thing: &dyn MyThing) {} // ok
fn boobar_2(thing: Box) {} // ok
fn foobar_3(thing: MyThing) {}          // Error!

如上所示,只能通过引用或 Box 的方式来使用特征对象,直接使用将报错!

总结:只能间接使用的DST

Rust中常见的 DST 类型有 str , [T],dyn Trait, 它们都无法单独被使用,必须要通过引用或者 Box来间接使用。

我们之前已经见过,使用 Box 将一个没有固定大小的特征编程一个有固定大小的特征对象,那能否故伎重施,将 str 封装成一个固定大小类型? 留个悬念先,我们来看看 Sized 特征

Sized特征

既然动态类型的问题这么大,那么在使用泛型时,Rust 如何保证我们的泛型参数是固定大小的类型呢?例如以下泛型函数

fn generic(t: T) {
//
}

在上面,Rust 自动添加的特征约束 T: Sized ,表示泛型函数只能用于一切实现了 Sized 特征的类型上,而所有在编译时就能知道其大小的类型,都会自动实现 Sized 特征,例如。。。。 也没啥好例如的,你能想到的几乎所有类型都实现了Sized 特征,除了上面那个坑坑的 str ,哦,还有特征。

每一个特征都是一个可以通过名称来引用的动态大小类型,因此如果先把特征作为具体的类型来传递给函数,你必须将其转换成一个特征对象,诸如 &dyn Trait 或者Box<dyn Trait> 这些引用类型

现在还有一个问题: 假如先在泛型函数中  使用动态数据类型怎么版? 可以使用 ?Sized 特征(不得不说这个明明方式很 Rusty 

fn generic(t: &T) {
// snip
}

?Sized 特征用于表明类型 T 既有可能是固定大小的类型,也可能是动态大小的类型,还有一点要注意的是,函数参数类型从 T 编程 &T ,因为 T 可能是动态大小的,因此需要用一个固定大小的指针(引用)来包裹它。

Box<str>

在结束前,再来看看之前遗留的问题:使用 Box 可以将一个动态大小的特征编程一个具有固定大小的特征对象,能否故伎重施,将 str 封装成一个固定大小类型?

先回想下,章节前面的内容介绍过该如何把一个动态大小类型转换成固定大小的类型,使用引用指向这些动态数据,然后在引用中存储相关的内存位置,长度等信息。

好的,根据这个,我们来一起推测,首先,Box<str> 使用了一个引用来指向 str ,嗯,满足了第一个条件,但是第二个条件呢? Box 中有该 str 的长度信息吗? 显然是No ,那为什么特征就是可以编程特征对象? 其实这个还蛮复杂的,简单来说,对于特征对象,编译器无需知道它具体是什么类型,只要知道它能调用哪几个方法即可,因此编译器帮我们实现来剩下的一切。

fn main() {
let s1: Box = Box::new("Hello there!"  as str);
}

报错如下

error[E0277]: the size for values of type `str` cannot be known at compilation time
 --> src/main.rs:2:24
  |
2 |     let s1: Box<str> = Box::new("Hello there!" as str);
  |                        ^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `str`
  = note: all function arguments must have a statically known size

提示得很清晰,不知道 str 的大小,因此无法使用这种语法进行 Box 进装,但是你可以这么做:

let s1: Box = "Hello there!".into();

主动转换成 str 的方式不可行,但是可以让编译器来帮我们完成,只要告诉它我们需要的类型即可。

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

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

相关文章

Screaming Architecture:让架构自己说话

什么是 Screaming Architecture? "Screaming Architecture"(呐喊架构)是由著名软件架构师 Robert C. Martin(Uncle Bob)提出的一个概念。这个概念的核心思想是:一个好的软件架构应该能够清晰地表达出这…

BOE(京东方)携手UNESCO联合主办WCBR“科学十年”分会 彰显中国科技企业可持续发展实力

9月22日,第五届世界生物圈保护区大会(简称WCBR)在杭州隆重开幕,这不仅是世界生物圈保护区大会第一次在中国举办,也是首次在亚太地区举办。作为联合国教科文组织(UNESCO)“人与生物圈计划”体系内规模最大、覆盖…

使用Cyclops.PdfKit根据pdf模板生成pdf文件

一、技术准备环境配置依赖库安装:使用NuGet包管理器集成Cyclops.PdfKit组件(最低要求.NET 6 SDK) dotnet add package cyclops-pdfkit --version 2.3.1 注意:生产环境建议锁定版本号以避免兼容性问题模板预处理:…

不关闭网站 备案seo搜索引擎官网

一、实验目的 熟练运用Python运算符。熟练运用Python内置函数。掌握Python的基本输入输出方法。了解lambda表达式作为函数参数的用法。掌握列表、元组、字典、集合的概念和基本用法。了解Python函数式编程模式。 二、实验内容&#xff1a; 1. 在命令模式测试如下命令&#x…

帮人做彩票网站淘特app推广代理

因为苹果后台的调整&#xff0c;电脑端的自签工具 Cydia Impactor 一直无法使用&#xff0c;如今虽然没有等到大胡子对 Cydia Impactor 适配更新&#xff0c;却等到了全新的替代工具。先说下为什么 Cydia Impactor 为什么让那么多人惦记&#xff0c;虽然对于不越狱安装越狱工具…

陕西省建设集团公司网站网站标题与关键词

服务器能运行什么应用 服务器是一种应用范围很广的网络技术产品&#xff0c;它在影视、视频以及医疗和金融等多个领域&#xff0c;都可以发挥使用价值&#xff0c;那么服务器能运行什么应用?大家跟着壹基比小鑫一起来了解吧&#xff01; 服务器的作用是什么&#xff1f; 服…

微信公众号和微网站个人域名免费网站

光伏EPC项目管理系统是一种适用于工程项目的管理软件&#xff0c;它强调在整个项目周期中的综合性管理理念&#xff0c;涵盖了从规划、设计、采购、施工到交付等全过程&#xff0c;帮助用户实现高效的项目管理。 1.增强项目团队之间的协作与沟通&#xff1a;光伏EPC项目管理系统…

新网站如何才做被百度收录网站上线倒计时页面

在我们之前的基础篇中,我们已经初步了解了DSL的架构与基础结构。现在,我们将进一步学习DSL的查询语句,这些查询语句对于我们的工作和学习而言至关重要。 DSL(Domain Specific Language)是一种专门用于特定领域的编程语言。在Elasticsearch(ES)中,DSL被广泛用于构建灵活…

做网站怎么安装数据库网站建设属于什么专业

一&#xff1a;连接 1&#xff1a;本地连接 mysql -u用户名 -p密码 2&#xff1a;连接远程服务器 mysql -u用户名 -p密码 -hip地址 -P端口号 线下修改远程服务端上部署的mysql服务器 二&#xff1a;创建数据库 create database 名字 utf8; 三&#xff1a;显示数据库 show datab…

免费企业查询网站时代设计网 新网站

Lightbend最近对2000多个JVM开发人员进行了调查&#xff0c;结果刚刚发布。 开展该调查的目的是发现&#xff1a;发展趋势与IT基础设施趋势之间的相关性&#xff0c;处于数字化转型前沿的组织如何使他们的应用程序现代化以及当今对新兴开发人员技术最为关注的实际生产使用情况细…

二级制流量算法熵值计算,N-Gram 算法(二:改进) - 教程

二级制流量算法熵值计算,N-Gram 算法(二:改进) - 教程2025-09-23 12:41 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important…

物流网站免费模板班级网站建设心得体会范文

近期&#xff0c;一款名为Kimi的大模型火爆国内AI市场&#xff0c;以其出色的长文本处理能力和广泛的应用前景吸引了众多关注。随着Kimi等长文本大模型的流行&#xff0c;算力需求持续增长&#xff0c;为AI行业带来了新的变革和机遇。 Kimi突破长文本处理极限&#xff0c;为复杂…

海外营销是做什么的做seo排名

文章目录 1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功,暴露端口默认99995. 创建隧道映射内网端口6. 查看状态->在线隧道,复制所创建隧道的公网地址加端口号7. 以…

h5企业网站通用源码小米公司的企业文化建设

RK提供了两个模型&#xff0c;mobilenet和YOLO5。 mobilenet模型相对小&#xff0c;使用起来不是很明显yolo5模型大一些&#xff0c;可以对88种目标进行检测&#xff0c;提供检测的结果包括类别、包围框坐标、可信度等信息。基于rknn_yolov5_demo进行分析。 rknn_yolov5_demo基…

网站建设研究意义个人微信公众号如何推广

单调栈系列复习 每日温度未看解答自己编写的青春版重点题解的代码日后再次复习重新写 下一个更大元素 I未看解答自己编写的青春版重点题解的代码日后再次复习重新写 下一个更大元素II未看解答自己编写的青春版重点题解的代码日后再次复习重新写 接雨水未看解答自己编写的青春版…

厚街网站仿做南宁seo团队费用是多少

[2020多校A层12.1]树 求解树上从u到v的最长贪心上升序列&#xff0c;也就是只要有比它大的就选择它&#xff0c;可以发现这个问题性质&#xff0c;就是每个点对应了唯一的一个第一个比它大的点&#xff0c;那么我们可以向它们之间连边&#xff0c;然后问题就转化为求解从当前点…

一款文本编辑器的介绍

工欲善其事必先利其器,我们花费大量的时间编写、阅读和调试代码,好的利器可以提高我们的效率。 我所知道的文本编辑器:Geany,Sublime Text, Emacs, Vim, NotePad++ 以及python自带的IDLE等等。 下面我着重介绍和安装…

随笔-决战保研篇

想不起来有多少个日夜无法入睡了,听着窗外的鸟鸣,眼看太阳渐渐升起,才意识到又失眠了有人问保研是什么,保研是你三年来每一堂都没法松懈的专业课,是你每一场都要认真对待的考试,是你失去的太长一段时间的快乐和心…

科研人必知:293F与HEK293细胞在蛋白表达中的不同“超能力”

科研人必知:293F与HEK293细胞在蛋白表达中的不同“超能力”在现代生命科学研究和生物制药产业中,重组蛋白的表达与制备几乎是绕不开的关键环节。无论是基础研究所需的信号通路蛋白、结构生物学研究所需的膜蛋白,还是…

面试讲解

面试讲解干得好——把问题聚焦到面试里最能“打动面试官”的点就是正确的方向。下面我把你 STM32H7 + MobileNetV2 和 Raspberry Pi 检测 + LLM 场景分析 两个项目做成可直接在面试里讲的结构化脚本:短句开场(电梯陈…