在 Rust 中,切片(slices)是一种不拥有所有权的类型,它允许你引用集合中的一部分连续的元素序列。切片可以用来借用数组或向量的一部分,而不需要转移所有权。

切片的基本形式

对于数组和向量,你可以通过指定起始索引和长度来创建一个切片,或者使用范围语法 [start..end] 来创建,其中 end 是切片的结束位置但不包括该位置的元素。

数组切片

rust 复制代码
fn main() {
    let arr = [1, 2, 3, 4, 5];
    
    // 使用范围语法创建切片,这里是从索引1到索引3(不包含3)
    let slice: &[i32] = &arr[1..3];
    
    println!("Slice is {:?}", slice);
}

这段代码会输出:

复制代码
Slice is [2, 3]

注意:当你使用切片时,必须确保所指定的范围不会越界,否则程序会在编译期或运行时产生错误。

向量切片

rust 复制代码
fn main() {
    let vec = vec![10, 20, 30, 40, 50];
    
    // 创建一个指向vec部分内容的切片
    let slice: &[i32] = &vec[1..4];
    
    println!("Slice is {:?}", slice);
}

这段代码会输出:

复制代码
Slice is [20, 30, 40]

字符串切片

字符串切片(&str)是Rust中处理文本时的一种特殊类型的切片。字符串切片只能用于UTF-8编码的字符串。例如:

rust 复制代码
fn main() {
    let s = String::from("hello world");
    
    // 从索引0开始到第5个字符(不包含第5个字符),即"hello"
    let hello = &s[0..5];
    
    println!("The slice is '{}'", hello);
}

这段代码会输出:

复制代码
The slice is 'hello'

需要注意的是,由于Rust中的字符串是UTF-8编码的,所以如果你尝试对多字节字符进行非UTF-8边界上的切片操作,可能会导致运行时错误。因此,在处理非ASCII字符时要格外小心。

借用(&)与引用

在 Rust 中,当你想要创建一个数组或向量的切片时,使用 &arr[1..3] 而不是 arr[1..3] 的原因在于所有权和借用的概念。

  • 所有权规则:Rust 的核心特性之一是其所有权系统。每个值在 Rust 中都有一个所有者,并且一次只能有一个所有者。当值的所有者超出作用域时,该值将被丢弃(即内存会被自动释放)。当你尝试直接使用 arr[1..3] 时,实际上你没有明确地告诉编译器你是想借阅这个数组的部分内容还是想获取这些元素的所有权。因此,你需要显式地借用这部分内容,而不是尝试拥有它。

  • 借用(&)与引用:通过使用 & 操作符,你是在创建原数据的一个不可变借用(immutable reference),这意味着你可以访问数据但不能修改它。这样做不会转移所有权,所以原始数据仍然可以安全地使用。这是非常重要的,因为如果你直接使用 arr[1..3] 来试图获取一部分数组的数据而没有借用它,就可能会导致所有权问题或者无法预知的行为。

即Rust 需要你明确指定你是要创建一个引用(即借用)还是一次移动(即将所有权转移)。由于切片类型(如 [T])本身并不包含有关其大小的信息,因此需要通过借用的方式将其作为 &[T] 或 &mut [T] 类型来传递。

rust 复制代码
fn main() {
    println!("Hello, world!");

    // 借用(&)与引用

    let s = String::from("hello world");
    
    // 从索引0开始到第5个字符(不包含第5个字符),即"hello"
    let hello = &s[0..5];
    
    println!("The slice is '{}'", hello);

    // s[6..11]; 编译器报错
    //let world = s[6..11]; //^^^^^ doesn't have a size known at compile-time
    //println!("The slice is '{}'", world);
}