Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

切片 &[T]

本集目標

用切片(slice)取出陣列的一部分,像透過窗戶看裡面的東西。

正文

有時候你不需要整個陣列,只想看其中一段。比如一個有 5 個元素的陣列,你只想看第 2 到第 4 個。這時候就可以用切片(slice)。

基本語法

fn main() {
    let arr = [1, 2, 3, 4, 5];
    let slice = &arr[1..4];
    println!("{:?}", slice);
}

和陣列、tuple 一樣,切片也只能用 {:?} 來印,不能用 {}

&arr[1..4] 的意思是:「從索引 1 開始,到索引 4 之前為止。」

  • 索引 1 → 2(包含)
  • 索引 2 → 3(包含)
  • 索引 3 → 4(包含)
  • 索引 4 → 5(不包含

所以結果是 [2, 3, 4]

範圍的寫法

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

    let a = &arr[0..3];  // [1, 2, 3]       從 0 到 3(不含 3)
    let b = &arr[0..=2]; // [1, 2, 3]       從 0 到 2(包含 2)
    let c = &arr[2..];   // [3, 4, 5]       從 2 到最後
    let d = &arr[..3];   // [1, 2, 3]       從頭到 3(不含 3)
    let e = &arr[..];    // [1, 2, 3, 4, 5] 整個陣列

    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
    println!("{:?}", d);
    println!("{:?}", e);
}
  • 1..4 → 從 1 到 4(不含 4)
  • 1..=3 → 從 1 到 3(包含 3),還記得第一章第 20 集的 ..= 嗎?一樣的用法
  • 2.. → 從 2 到結尾
  • ..3 → 從開頭到 3(不含 3)
  • .. → 整個

切片是「視窗」,不是「複製」

這裡有個重要的觀念:切片不是把資料複製一份出來,而是「指向原本陣列的某一段」。就像透過窗戶看房間裡的東西——東西還是在房間裡,你只是從窗戶看進去。

fn main() {
    let arr = [10, 20, 30, 40, 50];
    let slice = &arr[1..4];
    
    println!("陣列:{:?}", arr);
    println!("切片:{:?}", slice);
}

那個 & 是什麼?

你可能注意到切片前面有個 &。這個符號代表「借用」(borrow),是 Rust 最重要的概念之一。但現在不用深入理解——先記住「切片要加 &」就好,之後我們會詳細解釋。

現在你只需要知道:寫切片的時候前面要加 &

切片的型別

還記得陣列的型別是 [i32; 5](型別包含長度)嗎?切片的型別是 &[i32]——沒有長度

fn main() {
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    let slice: &[i32] = &arr[1..4];
    println!("{:?}", slice);
}

&[i32] 代表「一段 i32 的切片」,不管長度是多少。這是切片和陣列最大的不同——陣列的長度是型別的一部分([i32; 3][i32; 5] 是不同型別),但切片不管長度,&[i32] 可以指向任意長度的連續區段。

走訪切片

切片也可以用 for 走訪:

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

    for x in slice {
        println!("{}", x);
    }
}

複合型別

學完切片之後,讓我們整理一下:到目前為止,我們學過兩類型別。

基本型別(primitive types): i32f64boolchar 等等,每個值就是一個單獨的東西。

複合型別(compound types): 把其他型別組合在一起的型別。我們已經學了三種:

  • tuple(i32, f64, bool) — 可以裝不同型別
  • 陣列[i32; 5] — 同一種型別,固定長度
  • 切片&[i32] — 同一種型別,不限長度

複合型別裡面的型別不一定要是基本型別,也能是一層複合型別套另一層複合型別:

fn main() {
    // 陣列裡面裝 tuple
    let pairs: [(i32, bool); 3] = [(1, true), (2, false), (3, true)];
    println!("{:?}", pairs);

    // tuple 裡面裝陣列
    let t: ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);
    println!("{:?}", t);

    // 陣列裡面裝陣列
    let grid: [[i32; 2]; 3] = [[1, 2], [3, 4], [5, 6]];
    println!("{:?}", grid);

    // 切片也是複合型別
    let arr: [i32; 5] = [10, 20, 30, 40, 50];
    let slice: &[i32] = &arr[1..4];
    println!("{:?}", slice);

    // tuple 裡面裝切片
    let pair: (&[i32], &[i32]) = (&arr[..2], &arr[3..]);
    println!("{:?}", pair);
}

重點整理

  • 切片用 &arr[start..end]&arr[start..=end] 取出陣列的一部分
  • start..end 是「包含 start、不包含 end」
  • start..=end 是「包含 start 也包含 end」
  • 切片是陣列的「視窗」,不是複製
  • 切片型別是 &[i32](不含長度),陣列型別是 [i32; 5](含長度)
  • 前面的 & 代表借用,之後會詳細解釋
  • 切片也可以用 for 走訪
  • tuple、陣列、切片都是複合型別——它們裡面可以裝其他型別,包含複合型別