跳到主要内容

切片

在 Rust 中,切片(slice)是对集合(如数组、String 等)中连续元素的引用,可以用来查看数据的一部分,而不需拥有数据的所有权。切片是一种轻量、灵活的方式来访问数组、字符串等集合中的部分数据。Rust 切片提供安全、有效的访问方式,避免了不必要的内存拷贝。

1. 什么是切片?

切片的类型表示为 &[T],其中 T 是集合中元素的类型,& 表示切片是一种引用。因此,切片是一种引用类型,它并不拥有数据。

  • 数组切片&[i32],表示对 i32 类型数组的引用。
  • 字符串切片&str,表示对字符串的引用。

2. 使用数组切片

数组切片允许我们访问数组中连续的元素,而不会改变数组的所有权。

例子:

fn main() {
let arr = [1, 2, 3, 4, 5];

let slice = &arr[1..4]; // 切片,从索引 1 到索引 4(不含)
println!("Slice: {:?}", slice);
}

在这里:

  • &arr[1..4] 表示从索引 1 到索引 4 的数组切片,不包括 4 本身。
  • slice 是一个 &[i32] 类型的切片,可以打印出 [2, 3, 4]

3. 使用字符串切片

在 Rust 中,字符串切片 &str 是对 String 或字符串字面量的一部分的引用,用于只读字符串数据。它可以避免不必要的拷贝。

例子:

fn main() {
let s = String::from("Hello, world!");

let slice = &s[0..5]; // 从索引 0 到索引 5 的字符串切片,不含 5
println!("Slice: {}", slice);
}

在这里:

  • &s[0..5] 表示从索引 0 到索引 5 的字符串切片(不包含 5),即 Hello
  • slice 是一个 &str 类型的切片,引用 s 的一部分数据。

4. 切片的特性

切片具有以下特性:

  • 只读访问:切片是数据的不可变引用,不能修改数据内容。
  • 不拥有数据:切片不持有数据的所有权,当数据的所有者(如数组或字符串)释放时,切片也会失效。
  • 边界安全:Rust 会在编译时和运行时检查切片的边界,防止越界访问。

例子:

fn main() {
let arr = [10, 20, 30, 40, 50];

let slice = &arr[1..6]; // 错误:切片超出数组边界
println!("Slice: {:?}", slice);
}

编译器会报错,提示切片超出了数组的有效范围,这个特性确保了内存访问的安全性。

5. 可变切片

对于可变数组或字符串,可以创建可变切片来修改数据内容。可变切片表示为 &mut [T]&mut str,需要遵循 Rust 的借用规则,同一时间只能有一个可变引用。

例子:

fn main() {
let mut arr = [1, 2, 3, 4, 5];

let slice = &mut arr[1..4]; // 可变切片
slice[0] = 10; // 修改切片内容,实际上修改了原数组

println!("Array after modification: {:?}", arr);
}

在这里:

  • &mut arr[1..4] 是一个可变切片,允许修改原数组的元素。
  • 修改 slice 中的元素会反映到 arr 中,因为切片只是在引用数组的一部分。

6. 切片的生命周期

由于切片是引用类型,因此它的生命周期必须比其引用的数据短。Rust 会在编译时检查切片的生命周期,确保在数据释放后不会有无效引用。

7. 总结

  • 切片是一种对集合数据的连续部分的引用,分为不可变切片和可变切片。
  • 数组切片:如 &[i32],用于访问数组中的部分数据。
  • 字符串切片:如 &str,用于访问字符串中的部分数据。
  • 边界检查:Rust 在编译和运行时检查切片的边界,确保安全。
  • 不可变和可变:不可变切片用于只读访问,可变切片用于修改数据内容。