Rust 切片
切片是对连续序列一段的借用视图:&[T] / &mut [T] / &str,不拥有数据但提供安全边界访问。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust 切片
这个概念为什么出现
经常只想操作集合的一部分:
- 文件名中的扩展名
- 报文头几个字节
- 数组中的窗口
若每次都 copy 或转移整个所有权,成本高且别扭。切片提供胖指针式的借用视图(指针 + 长度)。
[!abstract] 一句话理解 切片
&[T](及&mut [T]、&str)借用一段连续元素并携带长度,在不拥有底层数据的前提下做安全、可索引的窗口访问。
最小可运行示例
场景:日志管道截取“首个空白前的 token”作为请求 ID
接入网关日志行:req-9f3a user=42 path=/pay。
需要只读取出第一个 token,而不修改/夺走整行 String。
// 业务意图:从日志行解析首 token 作为 request_id。
// 教学点:字符串切片 &str;切片是借用;返回的 &str 生命周期绑定输入。
fn first_token(line: &str) -> &str {
// 找到第一个空白;没有则整行
match line.find(char::is_whitespace) {
Some(i) => &line[..i], // 切片:半开区间 [0, i)
None => line,
}
}
fn main() {
let line = String::from("req-9f3a user=42 path=/pay");
let req_id = first_token(&line);
println!("request_id={req_id}");
// line 仍可用:只是被借用
println!("raw_len={}", line.len());
}
建议运行:
cargo run
期望输出:
request_id=req-9f3a
raw_len=27
结合场景再看三个关注点
- 返回
&str必须来自输入借用,不能指向函数内临时String。 - UTF-8 边界:字节索引必须落在字符边界,否则 panic。
- 数组也可切:
let a = [1,2,3,4]; let w = &a[1..3];
核心概念与准确模型
类型
| 类型 | 含义 |
|---|---|
[T] | 动态大小的切片类型本身(DST,少直接写) |
&[T] | 共享切片引用 |
&mut [T] | 可变切片引用 |
&str | 字符串切片(合法 UTF-8) |
语法
&data[start..end] // 半开
&data[start..=end] // 闭
&data[..end]
&data[start..]
&data[..]
与数组 / Vec
- 数组
[T; N]、Vec<T>可被借用为切片 - 函数参数写
&[T]可同时接受数组/Vec/切片
设计动机
- 统一“连续序列视图”的 API
- 零拷贝解析与窗口算法
- 与借用检查器协作,避免悬垂子视图
边界情况与反直觉行为
- 字符串不能按“第 n 个字符”廉价随机切而不考虑 UTF-8
- 越界切片 panic
- 可变切片拆分(
split_at_mut)允许无重叠的两个&mut [T]
常见误区
[!warning] 常见误区:把切片当成拥有数据的小 Vec 错误理解:切片自己有堆。
正确模型:切片只借用;所有者没了切片也不能活。
工程实践
- 库函数输入优先
&[T]/&str - 需要拥有再用
to_vec()/to_string() - 二进制协议解析大量使用切片窗口
本节总结
- 切片 = 借用 + 长度的连续视图
&str是字符串切片- 索引要注意边界与 UTF-8
自测题
- 为什么
fn f() -> &str { let s = String::from("a"); &s }非法? &[u8]与&str有何关系?
参考答案
- 返回引用指向即将 drop 的局部。
&str保证 UTF-8;&[u8]是任意字节切片。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — The Slice Type | 官方书 | 切片 |
| std::slice | 标准库 | API |