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

结合场景再看三个关注点

  1. 返回 &str 必须来自输入借用,不能指向函数内临时 String
  2. UTF-8 边界:字节索引必须落在字符边界,否则 panic。
  3. 数组也可切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 错误理解:切片自己有堆。
正确模型:切片只借用;所有者没了切片也不能活。

工程实践

  1. 库函数输入优先 &[T] / &str
  2. 需要拥有再用 to_vec() / to_string()
  3. 二进制协议解析大量使用切片窗口

本节总结

  • 切片 = 借用 + 长度的连续视图
  • &str 是字符串切片
  • 索引要注意边界与 UTF-8

自测题

  1. 为什么 fn f() -> &str { let s = String::from("a"); &s } 非法?
  2. &[u8]&str 有何关系?
参考答案
  1. 返回引用指向即将 drop 的局部。
  2. &str 保证 UTF-8;&[u8] 是任意字节切片。

延伸阅读与资料来源

资料类型支撑内容
The Book — The Slice Type官方书切片
std::slice标准库API
创建于 2026/7/15 更新于 2026/7/15