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