切片 (slice) 用于引用一个集合(比如数组、字符串)的一段连续部分(子集)而不需要拥有这些元素的所有权。

比较常见的用法有 字符串切片类型 &str

字符串字面量是 slice 类型,数据被硬编码在可执行二进制文件中,程序使用字符串切片来访问它。

字符串类型的变量有一个字符串数据在内存中起始位置的指针,表示有关字符串长度和容量的信息。

let sentence = String::from("This is a sequence of words.");
println!("sentence is {}", sentence); // sentence is This is a sequence of words.
let last_word = &sentence[22..22 + 5];
println!("last_word is \"{}\"", last_word); // last_word is "words"

last_word 变量有一个指向字符串数据部分的 偏移/起始 索引的指针以及切片长度。 通常切片的结束索引不包含在结果中。(不包含第 5 位)

从起始位置到末尾的切片:

let last_part: &str = &sentence[22..];
println!("last_part is \"{}\"", last_part); // last_part is "words."

字符串切片的长度以字节数为单位,使用 usize 类型。不是字符串中字符的数量

let slice_length: usize = last_part.len();
println!("slice_length is {} bytes", slice_length); // slice_length is 6 bytes

当使用字符串切片索引取值的时候应特别注意,UTF-8 编码会占用 1 到 4 字节,而不是固定的字节。索引值必须在字符的边界处,否则程序会 panic 。所以在创建字符串的时候谨慎使用特殊字符或是表情。

Node.js 中我们是不太会关注这些底层问题。

Slices 类型作为参数

我们创建一个函数用来获取一句话的第一个词语:

fn get_first_word(msg: &String) -> &str {
    // 从字符串语句中创建一个字节类型的 slice (&[u8])
    let bytes: &[u8] = msg.as_bytes();

    // 遍历这个 bytes ,并使用 enumerate() 获取每次的索引值
    for (index, &item) in bytes.iter().enumerate() {
        // 找到第一个空格,并将之前的所有内容作为 string slice 返回
        // 一个空格的字节表示为 b' '
        // 我们正在迭代的是 字节 而不是 字符串
        // 这样做是因为 索引值 是因为字符串切片的索引是以 字节 为单位的

        if item == b' ' {
            return &msg[..index];
       }
    }
    // 如果没有找到空格则返回全部
    &msg
}
let message = String::from("lorem ipsum");

let first_word = get_first_word(&message);
println!("first_word is \"{}\"", first_word); // first_word is "lorem"

let first_word_too = get_first_word_too(&message[6..]);
println!("first_word_too is \"{}\"", first_word_too); // first_word_too is "ipsum"