Rust 學習筆記:字串
2023年10月14日 · 中文
前言
本系列文書寫我個人初探 Rust 的學習筆記,章節劃分主要基於著名的 The Book,The Rust Programming Language,程式碼部分通常是個人閱讀消化後以方便說明的方式撰寫,完整學習建議直接參見該書。
The Rust Programming Language
該書也有中文翻譯版,不過個人閱讀以英文原版為主以鞏固對 terminology 的一致認識,我認為對未來閱讀以及查找資料會較為順暢。
不論語言該書都是相當優秀的學習資源,選擇適合你的語言開始學習 Rust 吧。
Appendix F: Translations of the Book
字串
字串在 Rust 中是相當複雜的,在 C 中字串只是一串 char
,而在 Rust 中字串則有很多的表現形式,其中最常使用到的是 String
與 &str
。
在 Rust 中字串與切片都是以 UTF-8 編碼的,通常情況我們並不需要擔心編碼的問題。
String
String 並不是 Rust 核心中內建的型別,他是在 std library 中提供的型別,因為它太常使用到因此包含在 prelude 中,會被 Rust 自動導入我們不需要手動導入它。
創建
以 new
方法建立空字串,或以 from
給予初始值。
let mut s = String::new(); let from = String::from("from"); println!("{from}"); // from
to_string
方法可將有 Display
trait 的型別轉換為 String。
let number_string = 5.to_string(); let literal_string = "literal".to_string(); println!("{number_string}"); // 5 println!("{literal_string}"); // literal
更新
建立可變字串,push
新增字元進字串,或以 push_str
新增字串切片,
let mut s = String::from("Hello"); s.push(' '); s.push_str("World."); println!("{s}"); // Hello World.
使用 +
運算子串接字串,s2
必須使用參考,s1
的所有權會被轉移到 s3
。
let s1 = String::from("Hello "); let s2 = String::from("world"); let s3 = s1 + &s2; println!("{s3}"); // Hello world
使用 format
macro 更方便的串接字串格式,用法類似 print
,format
使用的都是參考因此不會產生所有權的移轉。
let s1 = String::from("Hello "); let s2 = String::from("new "); let s3 = String::from("world"); let s = format!("{s1}{s2}{s3}"); println!("{s}"); // Hello new world // it's ok to use s1 s2 s3 println!("{s1}"); println!("{s2}"); println!("{s3}");
索引
Rust 不允許使用數字索引字串,因為 UTF-8 編碼每個字元的 byte 長度是不同的,會造成難以預期的結果,因此 Rust 不允許這樣的用法。
我們可以使用 chars
方法取回一個 iterator 來遍歷每個 char,這在英文不會有問題。
let s1 = String::from("Hello"); for char in s1.chars() { println!("{char}"); } // output: // H // E // L // L // O
但如過要使用其他語言可能會產生非預期的結果,如書上提供的印度語範例。
let s1 = String::from("नमस्ते"); for char in s1.chars() { print("{char} "); } // output: न म स ् त े
這會印出六個數值,這是因為 chars
取得的是 scalar values
,它不一定就是一般人認知的字母。
用另一種形式取得 grapheme clusters
會更接近一般人所認知的字母,這會需要引入 unicode_segmentation
crate。
use unicode_segmentation::UnicodeSegmentation; fn main() { let s1 = String::from("नमस्ते"); for i in s1.graphemes(true) { print!("{i} "); } } // output: न म स् ते
在使用切片時也會遇到類似的狀況,這邊我們必須給定 0..3
來取得 न
。
let s1 = String::from("नमस्ते"); println!("{}", &s1[0..3]); // न
總之在操作字串尤其非英文的語言時一定要留意這類情形。