Learn
Rust/07-slices

切片

切片(slice) 是「对一段连续序列的视图」,本身不拥有数据,只是借用。它让你安全地引用集合的一部分。

1. 字符串切片 &str

字符串切片
fn main() {
    let s = String::from("hello world");
    let hello = &s[0..5];     // "hello"
    let world = &s[6..11];    // "world"
    println!("{} + {}", hello, world);
}

&str 是「字符串切片」:一个指针 + 长度。字符串字面量 "abc" 的类型就是 &'static str——指向二进制里的只读数据。

ℹ️为什么函数参数用 &str 而非 &String

&str 既能接 String 的切片(&s[..]),也能接字面量。写 fn f(s: &str) 最通用;&String 只接受 String。

2. 切片是借用

对 s 取切片时,同时持有一个不可变借用。因此切片存活期间,不能对 s 做可变操作:

取第一个单词
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    for (i, &b) in bytes.iter().enumerate() {
        if b == b' ' {
            return &s[0..i];
        }
    }
    &s[..]
}
 
fn main() {
    println!("{}", first_word("hello world"));
    println!("{}", first_word("single"));
}
⚠️切片的边界检查

&s[0..100] 若越界会 panic。切片必须在 UTF-8 字符边界上切,否则编译/运行报错——Rust 不会让你把一个多字节字符劈成两半。

3. 数组切片

数组切片
fn main() {
    let arr = [1, 2, 3, 4, 5];
    let mid = &arr[1..4];     // [2, 3, 4],类型 &[i32]
    let sum: i32 = mid.iter().sum();
    println!("{:?}", mid);
    println!("{}", sum);
}

数组切片 &[T] 与 Vec<T> 的切片同理,都是「指针 + 长度」的胖指针。

4. 切片作为通用参数

很多 API 接受切片而非具体集合,便于复用:

fn largest(nums: &[i32]) -> i32 {
    *nums.iter().max().unwrap()
}
💡切片让函数更通用

接收 &[i32] 的函数,既能吃数组 &arr[..],也能吃 Vec 的 &vec[..]。优先用切片做只读接口。

5. 对比字符串与切片

类型拥有数据可修改典型用途
String是是需要构造/修改字符串
&str否(借用)否只读查看、函数参数
🎯练习

写一个 fn second_word(s: &str) -> &str 返回第二个单词(按空格切分)。对 "the quick brown" 调用,验证返回 "quick"。注意处理不足两个词时的边界。

小结

  • 切片是对连续序列的「视图」,胖指针(指针+长度)
  • &str 用于只读字符串,&[T] 用于数组/Vec 片段
  • 取切片即借用,与可变操作互斥
  • 函数参数优先用切片,通用且零拷贝
  • 下一章看结构体 →