ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【Rust自学】4.5. 切片(Slice) [打印本页]

作者: 羊蹓狼    时间: 2024-12-22 15:51
标题: 【Rust自学】4.5. 切片(Slice)
4.5.0. 写在正文之前

这是第四章的最后一篇文章了,在这里也趁便对这章做一个总结:
所有权、借用和切片的概念确保 Rust 步伐在编译时的内存安全。 Rust语言让步伐员能够以与其他系统编程语言雷同的方式控制内存使用情况,但是当数据所有者超出范围时,让数据所有者自动清理该数据意味着您无需编写和调试额外的代码来获得这个控制权
看完这篇文章,相信你会由衷的感叹Rust所有权机制到底有多么神奇和先辈。
喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
4.5.1. 切片的特性


4.5.2. 字符串切片

以一道题为例:
编写一个函数,它接受字符串作为参数,它返回它在这个字符串中找到的第一个单词,如果函数没找到任何空格,那么整个字符串就被返回。
  1. fn main() {
  2.         let s = String::from("Hello world");
  3.         let word_index = first_word(&s);
  4.         println!("{}", word_index);
  5. }
  6. fn first_word(s:&String) -> usize {
  7.         let bytes = s.as_bytes();
  8.         for (i, &item) in bytes.iter().enumerate() {
  9.                 if item == b' ' {
  10.                         return i;
  11.                 }
  12.         }
  13.         s.len()
  14. }
复制代码

步伐乐成编译,输出是5。也就是Hello后边的空格的索引位置
我们如今有办法找出字符串中第一个单词末端的索引,但是有一个问题。我们本身返回一个usize ,但它只是&String上下文中的一个故意义的数字。换句话说,因为它是与String不同的值,以是不能包管它在将来仍然有效
比如因为某些原因代码在调用first_word之后写了s.clean();这行来清空s,此时的word_index这个变量就没故意义了;也可以说,Rust编译器发现不了代码使用了s.clean()但word_index仍然存在的错误,如果你在之后的代码中还使用了word_index去打印字符,那显然就会发生错误。
这类的API(或者叫函数计划)要求随时关注word_index的有效性,确保这个索引和这个String变量s它们之间的同步性。偏偏这类工作每每相当繁琐而且特别容易出错,以是针对这类问题Rust提供了字符串切片
字符串切片是指向字符串中一部分内容的引用。
在原字符串名前加上&代表对它的引用,在后加上[开始索引..竣事索引],表示引用这个字符串的一部分。注意,[]内的区间是左闭右开,以是竣事索引是切片停止位的下一个索引值。顺口溜:包左不包右。
  1. fn main() {
  2.         let s = String::from("hello world");
  3.         let hello = &s[0..5];
  4.         let world = &s[6..11];
  5. }
复制代码
在这个例子中把s从0到5的索引区间(包罗0不包罗5),也就是"Hello"这部分赋给了hello这个变量;把从6到11的索引区间(包罗6不包罗11),也就是"world"这个部分赋给了world这个变量

由图可见,world这个变量并不会独立于s而存在,这样使得编译器能够在编译过程中就发现很多潜在的问题。
当然,对于索引的写法,还有几种省略的方式:
  1. let hello = &s[0..5];
复制代码
这个变量是从索引0开始截取的,Rust答应这样的等价写法:
  1. let hello = &s[..5];
复制代码
  1. let world = &s[6..11];
复制代码
这个变量截取到了s的最后一个元素,Rust答应这样的等价写法:
  1. let world = &s[6..];
复制代码
如果想截取整个字符串,那就可以:
  1. let whole = &s[..];
复制代码
注意事项


重写代码

学了切片之后,就可以修改文章开头的代码来进一步优化了:
  1. fn main() {
  2.         let s = String::from("Hello world");
  3.         let word = first_word(&s);
  4.         println!("{}", word);
  5. }
  6. fn first_word(s:&String) -> &str {
  7.         let bytes = s.as_bytes();
  8.         for (i, &item) in bytes.iter().enumerate() {
  9.                 if item == b' ' {
  10.                         return &s[..i];
  11.                 }
  12.         }
  13.         &s[..]
  14. }
复制代码

这个时间如果在word = first_word(&s);这一行之后加上s.clean();,Rust就能够发现错误并报错:
  1. error[E0502]:cannot borrow `s` as mutable because it is also borrowed as immutable
复制代码
因为在同一个作用域中出现了可变引用s.clean()和不可变引用&s,违反了借用规则
PS:s.clean()等价于clean(&mut s)
4.5.3. 字符串字面值就是切片

字符串字面值被直接存储在二进制步伐之中,在步伐运行时会被放入静态内存里
  1. let s = "Hello, World!";
复制代码
变量s的范例是&str,它是一个指向二进制步伐特定位置的切片。&str不可用,以是字符串字面值也是不可变的。
4.5.4. 将字符串切片作为参数通报

  1. fn first_word(s:&String) -> &str {
复制代码
这是刚刚优化过的代码中声明函数的那一行,这种写法本身完全没有任何问题。但有经验的Rust开发者会使用&str作为s的参数范例,因为这样就可以同时吸收String和&str范例的参数了:

定义函数时使用字符串切片来取代字符串引用会使APU更加通用,且不会损失任何功能。
根据它,还可以再进一步地优化之前的代码:
  1. fn main() {
  2.         let s = String::from("Hello world");
  3.         let word = first_word(&s);
  4.         println!("{}", word);
  5. }
  6. fn first_word(s:&str) -> &str {
  7.         let bytes = s.as_bytes();
  8.         for (i, &item) in bytes.iter().enumerate() {
  9.                 if item == b' ' {
  10.                         return &s[..i];
  11.                 }
  12.         }
  13.         &s[..]
  14. }
复制代码
这行:
  1. let word = first_word(&s);
复制代码
也可以写成:
  1. let word = first_word(&s[..]);
复制代码
对于前者,Rust会隐式调用Deref,将&String转换为&str;后者是手动转换为&str范例
4.5.5. 其他范例的切片

  1. fn main() {  
  2.     let number = [1, 2, 3, 4, 5];  
  3.     let num = &number[1..3];  
  4.     println!("{:?}", num);  
  5. }
复制代码
数组也可以使用切片。num这个切片的本质就是存储了指向number中切片截取的起始点(这个例子中是索引为1的位置)的指针与长度的信息。
其输出是:
  1. [2, 3]
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4