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

字串切片 &str

本集目標

認識 &str 這個型別,原來我們一直在用的字串就是切片!

正文

前幾集我們學了陣列的切片 &[i32]。今天來認識另一種切片——字串切片。其實我們之前寫的 "hello" 就是字串切片。

字串的真面目

fn main() {
    let s = "hello";
    println!("{}", s);
}

這段程式碼你已經看了無數次了。但 s 的型別是什麼?

答案是:&str(字串切片)。

fn main() {
    let s: &str = "hello"; // 明確標出型別
    println!("{}", s);
}

&str 唸作「string slice」或「ref string」。它就像陣列切片 &[i32] 一樣,是「指向一段資料的視窗」。

和陣列切片的對比

陣列切片字串切片
&[i32]&str
指向一段 i32 資料指向一段文字資料
let s = &arr[1..4];let s = "hello";

概念完全一樣!只是一個是數字的切片,一個是文字的切片。

字串切片也可以取子字串

fn main() {
    let s = "hello world";
    let hello = &s[0..5];
    let world = &s[6..11];
    println!("{}", hello); // hello
    println!("{}", world); // world
}

&s[0..5] 就是取 s 的前 5 個 bytes(注意是 bytes,不是字元)。

和陣列切片一樣,也可以用 ..= 來包含結尾:

fn main() {
    let s = "hello world";
    let hello = &s[0..=4]; // 包含索引 4,等同於 &s[0..5]
    println!("{}", hello); // hello
}

⚠️ 中文字串切片要小心!

英文字母一個字佔 1 個 byte,但中文字通常佔 3 個 bytes。如果你切的位置剛好在一個中文字的「中間」,程式會直接崩潰:

fn main() {
    let s = "你好";
    let first = &s[0..3]; // ✅ "你"(剛好 3 個 bytes)
    println!("{}", first);
}

但如果你試著切 &s[0..1]

fn main() {
    let s = "你好";
    let oops = &s[0..1];  // ❌ 程式崩潰!
    println!("{}", oops);
}

因為「你」佔了 3 個 bytes(索引 0、1、2),你切到索引 1 是這個字的「中間」,Rust 不允許這樣做。

簡單來說:對英文字串做切片很安全,但對中文字串做切片時,要確保切的位置剛好在字元的邊界上。如果不確定,先不要對中文字串用 &s[start..end]

函數參數用 &str

現在你知道字串是 &str 了,就可以把它當函數參數:

fn greet(name: &str) {
    println!("嗨,{}!", name);
}

fn main() {
    greet("Andy");
    greet("小明");
}

"Andy" 本身就是 &str 型別,所以直接傳進去就行。

重點整理

  • "hello" 的型別是 &str,就是字串切片
  • &str 和陣列切片 &[i32] 的概念一樣——都是「指向一段資料的視窗」
  • 函數參數寫 &str 就能接受字串
  • 也可以用 &s[start..end] 取子字串,但要小心:索引是 byte 位置,不是字元位置,切在中文等多 byte 字元的中間會 panic

恭喜你完成了第二章!🎉 這一章我們學到了更多組織程式的方法——函數、陣列、切片,還有各種讓程式碼更清晰的技巧。下一章我們將開始自訂型別,用 structenum 來描述你自己的資料!