Rust入门-07-切片

切片(slice

  • slice是一个没有所有权的数据类型

    • slice 允许引用集合中一段连续的元素序列,而不用引用整个集合
    //该函数接收一个字符串,返回在字符串中找到第一个单词
    //如果在字符串中没有找到空格,就返回整个字符串
    fn first_word(s: &String) -> usize {
        let bytes = s.as_bytes();       //as_bytes  将 String 转化为字节数组
    
        for (i, &item) in bytes.iter().enumerate() {   //使用iter方法在字节数组上创建一个迭代器                                                                      //iter会依次返回集合中的每一个元素                                                                            //enumerate 会包装 iter 的结果,
                                                       //并将这些元素作为元组的一部分来返回                                                                          //enumerate 返回的元组中,
                                                       //第一个元素是索引,第二个元素是集合中元素的引用
            if item == b' ' {
                return i;
            }
        }    
        s.len()
    }
    

    该代码有一个缺陷:函数返回的索引值 usize是独立的,只在&String的上下文中才有意义。那么当函数返回值以后,就无法保证其的有效性

    fn main() {
        let mut s = String::from("hello world");
    
        let word = first_word(&s); // word 的值为 5
        
        s.clear(); // 清空了字符串,使其变成一个空的字符串
        
        // 但 word 在此处的值仍然是 5,即索引的值仍然是 5 
        // 此时 word 的值是无效的,不能在 s 中找到对应的值
        // 即将 5 保存到word中时,s 的内容已经发生变化了
    }
    

    所以在设计这类问题时,需要时刻关注 word 的有效性,以及 s 和其索引值 word 的同步性

    这样会很繁琐

字符串切片(string slice

  • 字符串切片String 中一部分值的引用

    • 可以写为 &str
    let s = String::from("hello world");
    
    let hello = &s[0..5];   //即s中索引值为0,1,2,3,4的元素,包括0,但不包括5
    let world = &s[6..11];  
    
  • 形式:[开始索引..结束索引]

    • 开始索引就是切片起始位置的索引值
    • 结束索引是切片终止位置的下一个索引值

    world containing a pointer to the byte at index 6 of String s and a length 5

    ​ world 是从 s 字符串索引值从 6 到 11

  • 字符串切片的语法(语法糖

    • 如果从索引 0 开始,可以省略两个点号之前的值

      let slice = &s[0..2];

      let slice = &s[..2];

    • 如果切片包含String的最后一个字符,可以省略两个点号之后的值

      let slice = &s[3..len];

      let slice = &s[3..];

    • 如果切片指向String整个字符串,可以同时省略两个点号前后的值

      let slice = &s[0..len];

      let slice = &s[..];

  • 注意

    • 字符串 slice range 的索引必须位于有效的 UTF-8 字符(?边界内
    • 如果尝试从一个多字节字符的中间位置创建字符串 slice,则程序会报错而退出
  • 使用字符串切片重新写开头的例子

    fn first_word(s: &String) -> &str {     //原本的例子为 usize
        let bytes = s.as_bytes();           //现在的&str引用作为返回值
                                            //可以确保该引用持续有效
        for (i, &item) in bytes.iter().enumerate() {
            if item == b' ' {
                return &s[0..i];            //原本的例子为return i
            }                               //现在如果集合的元素为空格,就将其切片返回
        }
        &s[..]                              //原本的例子为 s.len
                                            //现在如果没有在集合中找到空格,就将其整个返回
    }
    

字符串字面值就是切片

  • s的类型就是&str

    • &str是不可变引用,所以字符串字面值也是不可变的
    let s = "Hello, world!";
    

字符串切片作为参数

  • 当用&str为参数类型时,可以同时接收String&str类型的参数

    fn first_word(s: &str) -> &str {

    • 使用字符串切片,可以直接调用该函数
    • 使用String,可以创建一个完整的String切片来调用函数
  • eg

    fn first_word(s: &str) -> &str {     //函数参数为 &str
        let bytes = s.as_bytes();
    
        for (i, &item) in bytes.iter().enumerate() {
            if item == b' ' {
                return &s[0..i];
            }
        }
        &s[..]
    }
    
    fn main() {
       
        let word = first_word(&my_string[0..6]);   //函数可以接收String的部分切片
        let word = first_word(&my_string);         //或者全部的切片
        
        let my_string_literal = "hello world";     //这个为字符串字面量
        let word = first_word(&my_string_literal[0..6]);//函数可以接受字符串变量的部分切片
        let word = first_word(my_string_literal);   //或者全部的切片
    }
    

其他类型的切片

  • 引用数组的一部分(数组切片

    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3];
    
posted @ 2022-04-29 20:12  ragworm  阅读(36)  评论(0)    收藏  举报