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

news2025/1/3 22:53:57

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.coloradmin.cn/o/2269100.html

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

相关文章

svn分支相关操作(小乌龟操作版)

在开发工作中进行分支开发&#xff0c;涉及新建分支&#xff0c;分支切换&#xff0c;合并分支等 新建远程分支 右键选择branch/tagert按钮 命名分支的路径名称 点击确定后远程分支就会生成一个当时命名的文件夹&#xff08;开发分支&#xff09; 分支切换 一般在开发阶段&a…

24年收尾之作------动态规划<六> 子序列问题(含对应LeetcodeOJ题)

目录 引例 经典LeetCode OJ题 1.第一题 2.第二题 3.第三题 4.第四题 5.第五题 6.第六题 7.第七题 引例 OJ传送门 LeetCode<300>最长递增子序列 画图分析: 使用动态规划解决 1.状态表示 dp[i]表示以i位置元素为结尾的子序列中&#xff0c;最长递增子序列的长度 2.…

蓝牙|软件 Qualcomm S7 Sound Platform开发系列之初级入门指南

本文适用范围 ADK24.2~ 问题/功能描述 S7开发环境搭建与编译介绍 实现方案 本文介绍适用于windows平台Application部分,audio ss的说明会在下一篇文章在做说明,Linux平台如果不进行AI算法的开发,个人认知是没有必要配置,若是做服务器倒是不错的选择.因为编译完成后烧录调试还…

Redis - 4 ( 9000 字 Redis 入门级教程 )

一&#xff1a; Zset 有序集合 1.1 常用命令 有序集合在 Redis 数据结构中相较于字符串、列表、哈希和集合稍显陌生。它继承了集合中元素不允许重复的特点&#xff0c;但与集合不同的是&#xff0c;有序集合的每个元素都关联一个唯一的浮点分数&#xff08;score&#xff09;…

ubuntu 使用samba与windows共享文件[注意权限配置]

在Ubuntu上使用Samba服务与Windows系统共享文件&#xff0c;需要正确配置Samba服务以及相应的权限。以下是详细的步骤&#xff1a; 安装Samba 首先&#xff0c;确保你的Ubuntu系统上安装了Samba服务。 sudo apt update sudo apt install samba配置Samba 安装完成后&#xff0c…

打印进度条

文章目录 1.Python语言实现(1)黑白色(2)彩色&#xff1a;蓝色 2.C语言实现(1)黑白颜色(2)彩色版&#xff1a;红绿色 1.Python语言实现 (1)黑白色 import sys import timedef progress_bar(percentage, width50):"""打印进度条:param percentage: 当前进度百分比…

深度解析 LDA 与聚类结合的文本主题分析实战

🌟作者简介:热爱数据分析,学习Python、Stata、SPSS等统计语言的小高同学~🍊个人主页:小高要坚强的博客🍓当前专栏:《Python之文本分析》🍎本文内容:深度解析 LDA 与聚类结合的文本主题分析实战🌸作者“三要”格言:要坚强、要努力、要学习 目录 引言 技术框架…

点跟踪基准最早的论文学习解读:TAP-Vid: A Benchmark for Tracking Any Point in a Video—前置基础

TAP-Vid: A Benchmark for Tracking Any Point in a Video— TAP-Vid&#xff1a;跟踪视频中任意点的基准、 学习这一篇文章的本来的目的是为了学习一下TAP-NET便于理解后面用到的TAPIR方法的使用。 文章目录 TAP-Vid: A Benchmark for Tracking Any Point in a Video— TAP-V…

C进阶-字符串与内存函数介绍(另加2道典型面试题)

满意的话&#xff0c;记得一键三连哦&#xff01; 我们先看2道面试题 第一道&#xff1a; 我们画图理解&#xff1a; pa&#xff0c;先使用再&#xff0c;pa开始指向a【0】&#xff0c;之后pa向下移动一位&#xff0c;再解引用&#xff0c;指向a【1】&#xff0c;a【1】又指向…

PH47代码框架 24241231 重要更新

仪式感一下&#xff1a;2024年最后一天&#xff0c;发布 PH47 代码框架的一次重要更新。当然这并不是有意的&#xff0c;而是直到现在才把更新的所有工作全部做完&#xff08;希望确实如此&#xff09;。 本次更新要点&#xff1a; 1、加入多IMU支持。本次更新正式加入对 MPU65…

idea报错:There is not enough memory to perform the requested operation.

文章目录 一、问题描述二、先解决三、后原因&#xff08;了解&#xff09; 一、问题描述 就是在使用 IDEA 写代码时&#xff0c;IDEA 可能会弹一个窗&#xff0c;大概提示你目前使用的 IDEA 内存不足&#xff0c;其实就是提醒你 JVM 的内存不够了&#xff0c;需要重新分配。弹…

Python用K-Means均值聚类、LRFMC模型对航空公司客户数据价值可视化分析指标应用|数据分享...

全文链接&#xff1a;https://tecdat.cn/?p38708 分析师&#xff1a;Yuling Fang 信息时代的来临使得企业营销焦点从产品中心转向客户中心&#xff0c;客户关系管理成为企业的核心问题&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 客户关系管理的关键是客…

Linux umami网站统计工具自定义API开发

Linux umami网站统计工具自定义API开发 一、src/queries/analytics/下添加调用sql查询文件&#xff1a;二、src/queries/index.js文件中增加导出模块内容&#xff1a;三、src/pages/api/下根据目录添加接口方法文件&#xff1a;四、构建项目&#xff0c;启动。1、到umami目录&a…

基于SpringBoot的实验室信息管理系统【源码+文档+部署讲解】

系统介绍 视频演示 基于SpringBootVue实现的实验室信息管理系统采用前后端分离的架构方式&#xff0c;系统分为管理员、老师、用户三种角色&#xff0c;实现了用户管理、设备管理、实验室查询、公告、课程、实验室耗材管理、我的等功能 技术选型 开发工具&#xff1a;idea2…

【openGauss】正则表达式次数符号“{}“在ORACLE和openGauss中的差异

一、前言 正则作为一种常用的字符串处理方式&#xff0c;在各种开发语言&#xff0c;甚至数据库中&#xff0c;都有自带的正则函数。但是正则函数有很多标准&#xff0c;不同标准对正则表达式的解析方式不一样&#xff0c;本次在迁移一个ORACLE数据库到openGauss时发现了一个关…

SSM-Spring-IOC/DI对应的配置开发

目录 一、IOC 控制反转 1.什么是控制反转呢 2. Spring和IOC之间的关系是什么呢? 3.IOC容器的作用以及内部存放的是什么? 4.当IOC容器中创建好service和dao对象后&#xff0c;程序能正确执行么? 5.Spring 容器管理什么内容&#xff1f; 6.如何将需要管理的对象交给 …

docker中使用nginx

宿主机和docker中nginx做映射 宿主机中nginx 映射目录 /root/myDockerData/devnginx 在容器中相关位置分别是&#xff1a; 配置文件位置&#xff1a;/etc/nginx/ 日志位置&#xff1a;/var/log/nginx/ 项目位置&#xff1a;/usr/share/nginx/html 如下配置启动命令行&#x…

Rocky Linux下安装meld

背景介绍&#xff1a; meld是一款Linux系统下的用于 文件夹和文件的比对软件&#xff0c;非常常用&#xff1b; 故障现象&#xff1a; 输入安装命令后&#xff0c;sudo yum install meld&#xff0c;报错。 12-31 22:12:17 ~]$ sudo yum install meld Last metadata expirat…

Python中PDF转Word的技术

Python PDF转Word技术概述 在日常办公和数据处理中&#xff0c;经常需要将PDF文档转换为Word文档&#xff0c;以便进行编辑、修改或格式调整。Python作为一种强大的编程语言&#xff0c;提供了多种库和工具来实现这一功能。以下是对Python中PDF转Word技术的详细介绍。 一、技…

混合并行训练框架性能对比

混合并行训练框架性能对比 1. 框架类型 DeepSpeed、Megatron - LM、Colossal - AI、SageMaker、Merak、FasterMoE、Tutel、Whale、Alpa、DAPPLE、Mesh - TensorFlow 2. 可用并行性(Available parallelisms) DNN framework(深度神经网络框架)DP(数据并行,Data Parallelis…