坏蛋Dan
知乎@坏蛋Dan
发布时间:2024.1.3

前言

昨天学完了vector

坏蛋Dan:rust基础学习--day15

今天该学String


String

这玩意儿应该算是我们用的最多的类型了,但是这玩意儿居然是一个集合collection,是一堆UTF-8字符char的集合?

实际上并不是,rust开发者将String定义为一堆bytes字节的集合。

rust的核心代码里是没有String的,只有字符串切片str,基本上都是&str,它是一些存储在某些地方的UTF-8字符char数据的引用。比如你声明的字符串字面量

String上面文章说过了,是标准库里的类型。和字符串切片不同的是,它可变、拥有所有权。

有一点需要强调的一点是,不管是str还是String,它们都是基于UTF-8编码的。如果使用超出UTF-8范围的符号就会有问题。

另外,说一下rustString为啥是一个集合。它其实是一个wrapper包裹着一个vector,然后再加点限制、功能等。而这个vector是一个u8类型的vector

创建字符串

既然是包裹的vector,那么自然可以用和vectornew关联函数。

相信大家都很熟悉了,我们直接看例子吧

new是String的关联函数,返回一个String实例。

我们也习惯这么写了,如果有初始数据的话基本都是用下面这种

但其实,我们也可以用字符串切片来实现,这是之前从来没用过的。

使用to_string方法会返回一个字符串类型,并且拥有了所有权。

两个都可用,看你自己的习惯。


更新字符串

我们之前好像有用到过一个方法push_str的方法,来看下例子

push_str需要的参数类型是字符串切片。

或者我们可以用push添加char给这个字符串

但这两种方式未免会有些麻烦,如果可以和别的于艳一样使用+直接加起来那该多好。

rust确实有这种方式,但是做了一定的限制。来看下例子

两个字符串类型相加会直接报错,需要调整为下面这种

第二个参数相加的变量得是字符串切片,而第一个参数必须要是字符串类型(拥有所有权)。

为什么会这样呢?因为+操作符实际上会被转换为类似add的方法

可以看到第一个参数接受的是自己并且是拥有所有权,这也就意味着s1add完之后就失效了。

第二个参数则是一个字符串切片,但是我们明明用的是一个&String的参数。

这也就是我为什么要说是类似add方法了,还是有差别的。

可以看到使用&str也是可行的。

为什么可以这样呢。。。实际上是编译器帮我们把&String强制转换成了&str

另外,如果有多个字符串相加,那用+来写还是很麻烦,在js中,可以直接使用 ` ${}将多个字符串拼接到一起。

rust中虽然没这么方便,但是还是有差不多功能的,也就是format!,看到这个!大家应该都知道是一个macro了。来看下例子


通过下标获取字符串元素

js中,我们可以用过下标直接获取字符串的元素,但是在rust中这么做是不行的。

为什么不行呢?

我们来看下字符串内部表现[5]

前面说过了String实际上是Vec加了一层wrapper,里面的元素都是UTF-8编码的字符。

我们来看下两个例子

这个hello字符串的len长度是4Hola每一个字符逗占一个byte

来看这下俄语的长度,数了下应该是12,但实际上是24,为什么呢?因为一个俄语符号占两个byte,也就是双字节。

实际上中文也是双字节。

所以通过下标获取就会出问题,可能抓到的元素不是自己想要的。

为什么要用字节存储呢?我们再来看一个例子

“नमस्ते”这是一个印度语,看这个完全不知道有多长。。。。

而在电脑会把它们转换为

一个Vec

试想一下,如果不是这个类型,那么就会被切割成这样

而这里面其实有俩符号并不是符合要求的,只是无意义语气符号,然后就会变成

这样就错了。

所以rust会把他们会转换成u8类型,这样就能保留原始数据,到时候再转回来就不会有问题。

最后还有一个原因那就是时间复杂度,在rust中通过下标获取元素的时间复杂度为O(1)。但是这并不适用于字符串,因为字符串需要从头开始一直走到下标位置,为什么要这么做呢?因为并不确定有多少符号是正确有效的。


切割字符串(slicing Strings)

如果你真有这个需求,那就用切片的方式,不过在这之前,你得知道你截取的是啥语言,比如

前面说了,俄语符号占两个字节,所以这里截取的应该是Зд

如果你截取双字节符号是只截取了一半也就是一个字节,rust会直接崩溃


遍历字符串

由于符号字节占位不同,所以我们并不能直接遍历,来看下例子

chars会返回字符串的符号迭代器

这样打印出来的符号就是正常的。

当然,如果你想获取字节,你也可以直接用bytes方法


总结

相信看到这里,你也觉得rust里的字符串好麻烦,好复杂。。。但是这也是rust解决问题的一种方式吧,谁又能想到把字符串类型当做一个集合呢?

最后,如果觉得对你有帮助的话,请务必点个赞,谢谢~

参考

  1. ^rust-String https://doc.rust-lang.org/book/ch08-02-strings.html#storing-utf-8-encoded-text-with-strings
  2. ^rust-create-String https://doc.rust-lang.org/book/ch08-02-strings.html#creating-a-new-string
  3. ^rust-updating-string https://doc.rust-lang.org/book/ch08-02-strings.html#updating-a-string
  4. ^rust-index-of-string-element https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings
  5. ^rust-inernal-representtation https://doc.rust-lang.org/book/ch08-02-strings.html#internal-representation
  6. ^rust-slicing-strings https://doc.rust-lang.org/book/ch08-02-strings.html#slicing-strings
  7. ^rust-interate-strings https://doc.rust-lang.org/book/ch08-02-strings.html#methods-for-iterating-over-strings

发布于 2022-12-10 18:37・IP 属地广东