rust 学习(三)
Slice 类型
介绍
slice允许你引用集合中一段连续的元素序列,注意它是一种引用,它没有用所有权。
现在我们用一个题目示例来展示它的功能。
如题:我们要输入一个字符串,找到第一个空格,并输出它的位置,即第一个单词的位置结尾
假设,我们不适用slice
直接来解决这个问题
1 | // 由于不需要所有权因此用s的引用 |
结果显然是对的,但是如果我们后续将 s 改变,这个返回的下标数并不会跟随改变,如果强行使用,有可能会出现越界等不安全问题。
1 | fn main() { |
再次之后我们编写,第查找第二个单词结尾位时,就会接连着出错。为此,Rust 为我们提供了slice
。
字符串slice
字符串slice
是String
的部分值引用。
1 | let s = String::from("hello world"); |
这个slice
的用法有点像 python 的切片,同样可以省略开头与结尾
1 | let s = String::from("hello"); |
根据这个特性,我们可以重写first_word
方法,string slice
被记作&str
。
1 | fn first_word(s: &String) -> &str { |
回到我们哪个 bug
1 | fn main() { |
这个报错的原因与所有权有关,slice
拿到了String
的引用,clear()
方法会拿到String
的可变引用,将其清空,但是根据上一篇文章讲到的,可变引用和不可变引用时相斥的,因此其他不可变引用应当无效,但是实际上我们在后面使用了这个不可变引用,从而引发了问题。
因此,程序变得跟安全,接下来就可以写获得第二个甚至第三个等等的函数了。
字符串的本质
”字符串字面值就是slice
“。
1 | let s = "hello world!"; |
这里s
的类型是&str
:它是一个指向二进制程序特定位置的slice
,这也就是为什么说String
不可变的原因:&str
是不可变引用。
因此我们可以对程序继续优化
1 | fn first_word(s: &str) -> &str {} |
更改成这样的签名之后,这个函数就既可以输入&String
类型,也可以输入&str
类型的参数。
其他类型的slice
效果上大差不差
1 | let a = [1, 2, 3, 4, 5]; |
总结
Rust 的 slice 设计与现代的其他语言很相似,用法上大差不差,但是在使用的时候会更加注重所有权规则,对于我而言,这个引用的规则有点像我们后端遇到的读写锁,比如 Mysql 的 x 锁和 s 锁。读读不排斥,写写排斥,读写也排斥。