【Rust自学】8.4. String类型 Pt.2:字节、标量值、字形簇以及字符串的各类操作

8.4.0. 本章内容

第八章主要讲的是Rust中常见的集合。Rust中提供了很多集合类型的数据结构,这些集合可以包含很多值。但是第八章所讲的集合与数组和元组有所不同。

第八章中的集合是存储在堆内存上而非栈内存上的,这也意味着这些集合的数据大小无需在编译时就确定,在运行时它们可以动态地变大或变小。

本章主要会讲三种集合:Vector、String(本文) 和HashMap

喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

8.4.1. 不能使用索引来访问String

Rust中的String不同于其他语言,不能用索引访问。如下例:

fn main() {  let s = String::from("6657 up up");  let a = s[0];  
}

输出:

error[E0277]: the type `str` cannot be indexed by `{integer}`--> src/main.rs:3:15|
3 |     let a = s[0];|               ^ string indices are ranges of `usize`|= help: the trait `SliceIndex<str>` is not implemented for `{integer}`, which is required by `String: Index<_>`= note: you can use `.chars().nth()` or `.bytes().nth()`for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>= help: the trait `SliceIndex<[_]>` is implemented for `usize`= help: for that trait implementation, expected `[_]`, found `str`= note: required for `String` to implement `Index<{integer}>`

报的错是类型String无法使用整数来进行索引,继续往下看到=help这一行,这里提示了String这个类型没有实现index<{integer}>(index是索引的意思,integer是整数的意思)这个trait。

8.4.2. String类型的内部表示

String类型是对Vec<u8>的包装,u8也就是byte字节。我们可以通过String上的len()方法来返回字符串的长度。如下例:

fn main() {  let len = String::from("Niko").len();  println!("{}", len);  
}

输出:

4

这个字符串采用的是utf-8编码,len的值为4也就是这个字符串占了4个字节,所以在这个例子里面每个字母就占用了一个字节。

但情况并不总是这样,比如说我们把字符串换成其他语言(这里是西里尔字母写的俄语):

fn main() {  let hello = String::from("Здравствуйте");  println!("{}", hello.len());  
}

如果你数一下这个字符串有12个字母,但是输出却是:

24

也就是说在这个语言里面一个字母会占用两个字节(中文是一个汉字占三个字节),而所谓的字母用一个专业术语来表示就是Unicode标量值,而西里尔字母每个Unicode标量值都对应两个字节。

通过这个例子你可以发现,String的数字索引并不能总是对应道一个完整的Unicode标量值,因为有的Unicode标量值会占不止一个字节,而数字索引注定只能读取到一个字节的值。

再举个例子,西里尔语里的З(不是数字)这个字母对应的是两个字节,而这两个字节的值分别是是208和151。假如说数字索引是允许的,那么我取Здравствуйте的索引0的值就会是208,而208本身又是无意义的字符(因为缺少第二个字节组不成一个Unnicode标量值)。所以为了避免这种无法立即发现的bug,Rust封杀了数字索引String,也就是在开发的早期阶段杜绝可能的误解。

8.4.3. 字节、标量值、字形簇

Rust中有三种看待字符串的方式:字节(Bytes)、标量值(Scalar Values)和字形簇(Grapheme Clusters)。其中字形簇是最接近我们说说的字母的概念的。

1. 字节

看个例子:

fn main() {  let s = String::from("नमस्ते");  //梵文书写的印度语for b in s.bytes() {  print!("{} ", b);  }  
}

这个梵文看起来好像有4个字母组成,我们使.bytes()这个方法来获得它所对应的字节,输出如下:

224 164 168 224 164 174 224 164 184 224 165 141 224 164 164 224 165 135

这里的18个字节就是计算机存储字符串的样子

2. 标量值

我们再来以Unicode标量值的形式来看待它:

fn main() {  let s = String::from("नमस्ते");  for b in s.chars() {  print!("{} ", b);  }  
}

使用.chars()方法能够获得这段字符串所对应的标量值,输出如下:

न म स ् त े 

它有4个实际的字母,而第四个和第六个标量值代表的是音标,单独存在没有任何意义,得于前面的东西放在一起算是一个字母。

这里也解释了为什么这个梵文实际上有18个字节,因为一个梵文占3个字节,这段字符串加上隐藏着的音标一共6个字符,把这两个数字相乘可以得到18这个数字,也就是18个字节。

3. 字形簇

因为从String里获得字形簇很复杂,所以Rust标准库没有提供这个功能,这里也就不做演示,但是可以去crate.io找第三方的库来实现这个功能。

总之,这串梵文如果以字形簇的格式打印出来会是:
请添加图片描述
这个样子。

8.4.4. 不能使用索引来访问String的原因

  • 数字索引取出来值的可能并不完整,无法组成一个Unicode标量值,导致无法第一时间察觉的错误
  • 索引操作会消耗一个常量时间,也就是O(1),而String无法保证这个时间,因为它需要从头到尾遍历所有内容从而确定有多少个合法的字符。

8.4.5. 切割String

可以使用[],在里面填上范围来创建字符串切片(关于字符串切片的详细内容在4.5. 切片(Slice),这里不再赘述)。如下例:

fn main() {  let hello = String::from("Здравствуйте");  let s = &hello[0..4];  println!("{}", s);  
}

刚才也说了一个西里尔字母占两个字节,这里的字符串切片切的是字符串的前4个字节,也就是前两个字母,看一下输出:

Зд

那如果字符串切片切的是2前三个字节呢?也就意味着切片的内容会是第一个字母加上半个第二个字母,这种情况会怎么样呢?看下面的例子:

fn main() {  let hello = String::from("Здравствуйте");  let s = &hello[0..3];  println!("{}", s);  
}

输出:

byte index 3 is not a char boundary; it is inside 'д' (bytes 2..4) of `Здравствуйте`

程序触发了panic!,错误信息是:索引3不是一个char边界。也就是说在切割的时候必须沿着char的边界来切割,对于这个西里尔语言来说就是2个2个字节地切割。

8.4.6. 遍历String

  • 对于标量值,使用.chars()方法。如下例:
fn main() {  let s = String::from("नमस्ते");  for b in s.chars() {  print!("{} ", b);  }  
}
  • 对于字节,使用.bytes()方法。如下例:
fn main() {  let s = String::from("नमस्ते");for b in s.bytes() {  print!("{} ", b);  }  
}
  • 对于字形簇,标准库未提供方法,但是可以找第三方库。

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

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

相关文章

1、pycharm、python下载与安装

1、去官网下载pycharm 官网&#xff1a;https://www.jetbrains.com/pycharm/download/?sectionwindows 2、在等待期间&#xff0c;去下载python 进入官网地址&#xff1a;https://www.python.org/downloads/windows/ 3、安装pycharm 桌面会出现快捷方式 4、安装python…

静默模式下安装Weblogic 14.1.1.0.0

目录 一、下载weblogic安装包二、安装JDK三、安装weblogic1、创建weblogic用户2、创建weblogic的安装目录3、上传并解压weblogic安装包4、创建 oraInst.loc 文件5、创建 wls.rsp 响应文件6、静默安装weblogic7、创建域8、启动Weblogic9、设置防火墙规则,以便其他服务器访问10、…

Windows安装Confluence详解

Confluence官网下载地址&#xff1a;https://www.atlassian.com/software/confluence/download-archives 建议安装confluence版本下载5.0-7.0之间&#xff0c;比较稳定一点&#xff0c;我安装的是6.8.2版本 centos7系统和阿里云服务安装后太卡了&#xff0c;果断放弃 Conflu…

Unity is running as administrator解决办法

每次打开Unity项目都会有这个弹窗 解决办法&#xff1a; 打开本地安全策略 - 安全选项 &#xff0c;把 用户账户控制&#xff1a;以管理员批准模式运行所有管理员 用户账户控制&#xff1a;用于内置管理员账户的管理员批准模式 改成已启用就行

springboot+vue实现SSE服务器发送事件

思路 一个基于订阅发布机制的SSE事件。客户端可以请求订阅api&#xff08;携带客户端id&#xff09;&#xff0c;与服务器建立SSE链接&#xff1b;后续服务器需要推送消息到客户端时&#xff0c;再根据客户端id从已建立链接的会话中找到目标客户端&#xff0c;将消息推送出去。…

【阻塞队列】- ArrayBlockingQueue 的原理-迭代器

文章目录 1. 前言2. 迭代器3. Itrs3.1 参数3.2 迭代器 Itr3.2.1 参数3.2.2 构造器3.2.3 hasNext3.2.4 next3.2.5 remove3.2.6 shutdown3.2.7 removedAt3.2.8 takeIndexWrapped 3.3 doSomeSweeping&#xff08;tryHandler&#xff09;3.4 register3.5 takeIndexWrapped3.6 remov…

人工智能与传统编程的主要区别是什么?

传统编程&#xff1a;开发者预先编写软件行为规则&#xff0c;代码基于程序员定义逻辑处理输入并产生确定输出&#xff0c;具有确定性、手动编写规则和结构化逻辑特点&#xff0c;如垃圾邮件分类程序基于预设关键词等规则。AI 编程&#xff1a;从数据中学习而非手动编写规则&am…

SpringBoot使用TraceId日志链路追踪

项目场景&#xff1a; ??有时候一个业务调用链场景&#xff0c;很长&#xff0c;调了各种各样的方法&#xff0c;看日志的时候&#xff0c;各个接口的日志穿插&#xff0c;确实让人头大。为了解决这个痛点&#xff0c;就使用了TraceId&#xff0c;根据TraceId关键字进入服务…

ts总结一下

ts基础应用 /*** 泛型工具类型*/ interface IProps {id: string;title: string;children: number[]; } type omita Omit<IProps, id | title>; const omitaA: omita {children: [1] }; type picka Pick<IProps, id | title>; const pickaA: picka {id: ,title…

八大排序——直接插入排序

直接插入排序&#xff08;Straight Insertion Sort&#xff09;&#xff0c;通常简称为插入排序&#xff0c;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。本文…

【QGIS入门实战精品教程】7.3:QGIS制作千层饼(DEM+等高线+影像+TIN)

文章目录 一、效果展示二、数据准备三、制作过程1. 打开软件2. 添加图层3. 制作千层饼一、效果展示 二、数据准备 订阅专栏后,从专栏配套案例数据包中的7.3.rar中获取。 1. dem 2. 影像 3. 等高线 4. tin 三、制作过程 1. 打开软件 打开QGIS软件。 QGIS软件主界面。

NetSuite Formula(HTML)超链打开Transaction

当Saved Search作为Sublist应用在Form时&#xff0c;如果Document Number是Group过的&#xff0c;则会出现如下超链失效的情况。 解决办法&#xff1a; 可以利用Saved Search中的Formula&#xff08;HTML&#xff09;功能来构建超链&#xff0c;用于打开Transaction。 以下图…

Springboot3.x整合swagger3

在网上看了许多教程&#xff0c;发现很多都是针对Spring Boot 2 框架的&#xff0c;即使有针对Spring Boot 3 的&#xff0c;用法也不太一样,配置项经常找不到类&#xff0c;经过对比测试&#xff0c;最后我使用的是 SpringDoc OpenAPI Starter WebMvc UI. pom为 <!--swag…

android.enableJetifier=true的作用:V4包的类自动编程成了androidx包的类,实现androidx的向下兼容

结论&#xff1a;引入androidx包后&#xff0c;可以兼容旧版本v4包的插件&#xff0c;把之前的 implementation com.yinglan.alphatabs:library:1.0.8 引入的组件中使用v4包的类&#xff0c;里面V4包自动反编译成 androidx包的类 结论; ‌V4包的类自动编程成了androidx包的…

详解MySQL在Windows上的安装

目录 查看电脑上是否安装了MySQL 下载安装MySQL 打开MySQL官网&#xff0c;找到DOWNLOADS 然后往下翻&#xff0c;找到MySQL Community(GPL) Downloads>> 然后找到MySQL Community Server 然后下载&#xff0c;选择No thanks,just start my download. 然后双击进行…

excel操作

来源&#xff1a;B站默默亚 一、版本识别 特点&#xff1a;向后兼容&#xff1b;高版本可以打开低版本&#xff0c;低版本不可以打开高版本 工作中&#xff0c;给老板最低版本&#xff0c;即2003版本 二、文件的扩展名 三、excel页面

最大化堡垒补给数量的策略与实现

最大化堡垒补给数量的策略与实现 问题描述输入格式输出格式问题分析解决方案代码实现代码解释问题描述 可怕的战争发生了,小度作为后勤保障工作人员,为了保卫国家而努力。现在有 N 个堡垒需要补给,然而总的预算 B 是有限的。每个堡垒需要价值 P(i) 的补给,并且需要 S(i) 的…

手机实时提取SIM卡打电话的信令声音-双卡手机来电如何获取哪一个卡的来电

手机实时提取SIM卡打电话的信令声音 --双卡手机来电如何获取哪一个卡的来电 一、前言 前面的篇章《手机实时提取SIM卡打电话的信令声音-智能拨号器的双SIM卡切换方案》中&#xff0c;我们论述了局域网SIP坐席通过手机外呼出去时&#xff0c;手机中主副卡的呼叫调度策略。 但…

国产手机嘴上喊着挑战苹果,实际行动却已承认失败,真的干不过

国产手机年年喊着挑战苹果&#xff0c;在苹果的iPhone15和iPhone16都被诟病创新不足的时候&#xff0c;国产手机更是以为迎来了赶超苹果的机会&#xff0c;然而随着年底的到来&#xff0c;诸多国产手机品牌的实际行动却说明他们其实已经承认败给苹果了。 近几周&#xff0c;国产…

微信小程序:定义页面标题,动态设置页面标题,json

1、常规设置页面标题 正常微信小程序中&#xff0c;设置页面标题再json页面中进行设置&#xff0c;例如 {"usingComponents": {},"navigationBarTitleText": "标题","navigationBarBackgroundColor": "#78b7f7","navi…