【Rust指南】结合String深入理解Rust语言的Slice切片类型

在这里插入图片描述


前言

  书接上文,本篇博客将通过结合有关字符串的Rust案例来深入理解并掌握Slice类型。旨在精准的学会切片类型的创建、作为函数的参数以及返回值以及语法糖的扩展等,同时也会分享到其他数据类型的切片,例如数组。


Rust Slice(切片)类型

切片(Slice)是对数据值的部分引用,是一种不持有所有权的数据类型。

切片这个名字往往出现在生物课上,我们做样本玻片的时候要从生物体上获取切片,以供在显微镜上观察。在 Rust 中,切片的意思大致也是这样,只不过它属于数据的取材引用。

一、编写处理字符串的函数

这里提供两种实现方法:一是通过以往的知识直接用String类型来解答,另一种是学习过本文的字符串切片类型后再去解答。

1、目标函数特点

  • 接收字符串作为参数
  • 返回它在这个字符串里找到的第一个单词
  • 如果没有找到空格,将字符串全部返回

2、使用String粗略实现

既然是找到第一个单词,不妨找到第一个空格所在的索引,后续从头开始打印到索引位置即可:

fn main() {
    println!("切片的学习");
    let mut s =String::from("hello world");
    let index=first_world(&s);
    s.clear();//这里清空s字符串,但是仍然可以得到第一个空格的索引
    println!("第一个空格出现的索引为:{}",index);
}
fn first_world(str:&String)->usize{
    let bytes=str.as_bytes();
    for(i,&item) in bytes.iter().enumerate(){
        if item==b' '{
        return i;
        }
    }
    str.len()
}

运行结果:

在这里插入图片描述

这里创建String类型的s并赋值"hello world",第一个空格的索引应为5,接下来用first_world函数来实现。

  函数形参的类型是String的引用,返回值是usizestr.as_bytes()含义为将str字符串转换为一个字节数组bytes,然后我们开始用for循环对字节数组遍历:
  for(i,&item) in bytes.iter().enumerate()(i,&iten) 是一个元组,i是元组的索引,即每个i对应着一个item,要注意它是一个引用,我们加上&之后解引用就成了一个u8类型的值了;然后bytes.iter()是该字节数组的一个迭代器,会依次返回字节数组里的元素;enumerate()方法会将迭代器遍历的元素包装成一个个的小元组,而刚开始for循环里的元组实际上是一个模式匹配,用来解构返回的小元组从而得到字节数组中每个索引和每个索引对应的元素值。
  将每个元素值和b' '(b’A’是字节的数据类型' '内用来放置特定的字节,这里我直接填上一个空格)比较,如果相等就返回索引,也就是第一个空格的索引,如果遍历到最后都没有空格,那就返回整个字符串的长度。

在主函数中调用first_world方法,注意里面传入的是字符串的引用,而且必须加上&,这点是不同于C++的。并用index接收该函数的返回值。虽然程序写完了而且可以得到正确结果,但其实是有bug存在的:此时的字符串s和索引并没有关联,如果我把字符串清空,此时仍然可以输出索引位置,这很明显是不合理的,因此就要使用接下来分享的字符串切片来解决这个bug。

3、使用字符串切片完整实现

fn main() {
    println!("切片的学习");
    let str=String::from("hello rust");
    let new_str=first_world_slice(&str[..]);
    
    //str.clear();不可将变量同时借用为可变和不可变的状态
    println!("字符串中第一个单词是:{}",new_str);
    
}

fn first_world_slice(s:&str) ->&str{
    let bytes=s.as_bytes();
    for(i,&it) in bytes.iter().enumerate(){
        if it==b' '{
            return &s[..i]
        }
    }
    &s[..]
}

运行效果:

在这里插入图片描述


这里主函数调用函数时传参传入的是&str[. .],即为字符串str转换为完整的字符串切片类型;函数内的返回部分也做了修改,存在空格的话就直接返回其索引前的字符串切片,如果没有空格则返回整个字符串。如果这时候执行str.clear(),编译器就会提示错误,原因就是违反了变量租借的原则,由此可见Rust语言可以使一些API变得简单通用且可以在编译阶段就能阻止错误的发生。

 细心观察的朋友可以看到函数的返回值被我改成了字符串切片类型,这样就可以传入字符串或者字符串切片两种类型的参数了:

  • 传入的参数如果使字符串切片就直接写入
  • 如果传入的是字符串类型,那么就创建一个完整的字符串切片即可
  • 定义函数时使用字符串切片来代替字符串引用会使我们的API更加通用,且不会损失功能

二、字符串切片及其与字符串的区别

最简单、最常用的数据切片类型是字符串切片(String Slice)

例如:

fn main() {
    let s = String::from("broadcast");

    let part1 = &s[0..5];
    let part2 = &s[5..9];

    println!("{}={}+{}", s, part1, part2);
}
//运行结果:broadcast=broad+cast
  • Rust 中的字符串类型实质上记录了字符在内存中的起始位置和其长度
    • part1在内存中的起始位置和字符串s一致
    • part2在内存中的起始位置指向字符c
    • s的长度为9,part1长度为5,part2长度为4
  • &s[x..y]就是字符串切片类型的格式,取值上是前开后闭的: [ x , y ) [x,y) [x,y)
    • . .y 等价于 0. .y
    • x. . 等价于位置 x 到数据结束
    • . . 等价于位置 0 到结束
  • 注意事项
    • 字符串切片的范围索引必须发生在有效的utf-8字符边界内
      • 这是编码问题,后续文章会详细说明
    • 如果尝试从一个多字节的字符串切片中创建字符串切片,程序会报错并退出
      • 这是因为切片类型是没有所有权的

实际上,到目前为止你一定疑惑为什么每一次使用字符串都要这样写String::from("runoob") ,直接写 "runoob" 不行吗?

事已至此我们必须分辨这两者概念的区别了。在 Rust 中有两种常用的字符串类型:strString :

  • str 是 Rust 核心语言类型,就是本章一直在讲的字符串切片(String Slice),常常以引用的形式出现(&str)。

凡是用双引号包括的字符串常量整体的类型性质都是 &str :

let s = "hello";

这里的 s 就是一个 &str 类型的变量。

  • String 和 str 除了同样拥有一个字符开始位置属性和一个字符串长度属性以外还有一个容量(capacity)属性。

  • String 和 str 都支持切片,切片的结果是 &str 类型的数据。

注意:切片结果必须是引用类型,但开发者必须自己明示这一点

三、非字符串切片的使用

除了字符串以外,其他一些线性数据结构也支持切片操作,例如数组:

fn main() {
    let arr = [1, 3, 5, 7, 9];
    let part = &arr[1..3];
    for i in part.iter() {
        println!("{}", i);
    }
}
//运行结果为:3 5

这里的part是一个数组的切片,起始元素为arr数组的索引1的值,最后一个元素应为arr数组索引2的值
然后利用迭代器依次返回数组切片的元素值


上面的解释中用到了很多Rust的基本类型知识,如果对于Rust基本类型不熟悉的朋友可以看一下本专栏里的文章。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340