4.3 slice类型
Slice 类型 总结
切片(slice) 是 Rust 提供的一种特殊引用,它让你可以安全地引用集合(如字符串、数组)中的一段连续元素,而不需要拥有这些数据的所有权。slice 的引入,漂亮地解决了“用单独的索引表示子序列”带来的数据不同步问题。
1. 没有 slice 的痛点:索引与数据脱钩
如果写一个 first_word 函数,返回字符串中第一个单词结尾的索引:
fn first_word(s: &String) -> usize {
// 查找空格,返回索引,或整个长度
}
你会得到一个 usize,但这个数字和原字符串没有任何绑定关系。之后原字符串被清空或修改,索引依然存在,使用它就会产生逻辑错误,而编译器却无法察觉:
let mut s = String::from("hello world");
let word = first_word(&s); // 5
s.clear(); // s 变为 ""
// word 仍然是 5,但已毫无意义 —— 编译器不报错!
这种“飘忽不定的索引”极易滋生 bug。
2. 字符串 slice:&str
字符串 slice 是 String 中一部分的引用,写法是 &s[开始..结束]:
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
- slice 内部存的是指向原数据起始位置的指针和长度,并不拥有数据。
- 类型写作
&str(读作 “string slice”)。
省略写法:
&s[0..2]可简写为&s[..2](从头开始)&s[3..len]简写为&s[3..](到末尾)&s[..]是整个字符串的 slice
3. 用 slice 重写 first_word —— 数据与引用绑定
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i]; // 返回开头到空格前的 slice
}
}
&s[..] // 整个字符串
}
现在返回的 slice 和原始 String 是绑定在一起的。如果有人在持有 slice 时尝试修改原字符串,Rust 的借用规则会在编译时直接阻止:
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // 编译错误!
println!("the first word is: {word}");
错误信息:cannot borrow s as mutable because it is also borrowed as immutable。编译器确保 word 这个不可变引用存在时,不能对 s 进行可变借用。这样,“清空字符串导致索引失效”这类 bug 在编译期就被彻底消灭了。
4. 字符串字面值就是 slice
let s = "Hello, world!";
这里的 s 类型正是 &str——它是指向二进制文件中硬编码数据的 slice。所以字符串字面值天然不可变,它本身就是一种不可变引用。
5. 更通用的函数签名:&str 作为参数
有经验的 Rustacean 会这样写:
fn first_word(s: &str) -> &str { ... }
这比 &String 更灵活,因为:
- 可以直接接收字符串字面值
- 可以接收
&String(Rust 会自动通过 Deref 强制转换将其变为&str) - 可以接收字符串的一部分 slice
无论传入什么形式的字符串数据,都能正常工作,API 通用且零成本。
6. 其他类型的 slice
数组也可以取 slice:
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3]; // 类型 &[i32]
assert_eq!(slice, &[2, 3]);
和字符串 slice 一样,存的是第一个元素的指针和长度。所有集合类型(如 Vec<T>)都支持这类 slice。
核心结论
- slice 是一种引用,让你借用集合的一部分,而不用获取所有权。
- 它让子序列的引用和原数据在编译时保持强绑定,杜绝了“索引与数据脱节”的错误。
- 字符串字面值本质就是
&str。 - 参数用
&str比&String更通用、更符合 Rust 惯例。 - 所有权、借用、slice 三者协同,使得 Rust 能在编译期就保证内存安全,且没有任何运行时开销。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 emoeem!
评论




