Rust 學習筆記:Rust 中的字符串漫談
Rust 的字符串設計與大多數具有單一字符串類型的編程語言有所不同,有多種不同用途的字符串類型,並且 Unicode 安全的字符串設計和獨特的所有權機制都使 Rust 中的字符串對於初學者來說在某種程度上是違反直覺的。
Rust 中常用有兩種字符串:String
和 &str
,其中 String
可動態分配、修改,內部實現可以理解爲 Vec<u8>
,而 &str
是一個類型爲 &[u8]
的切片。這兩種字符串都只能保存合法的 UTF-8 字符。
Rust 中的字符串保證是有效的 UTF-8,可以參考這篇文章的說明 Rust 爲什麼要使用 UTF-8 (UTF-8 Everywhere :https://utf8everywhere.org)
而對於非肉眼可辨識的 UTF-8 字符,則可以考慮使用如下類型:
-
使用
OSString
和&OSStr
和操作系統交互 -
使用
CString
和&CStr
和 C 庫交互 -
文件路徑有專用的
Path
和PathBuf
-
字節字符串字面值 (byte string literals)
Vec<u8>
和&[u8]
String
& &str
字符串String
是由字符組成的連續集合,Rust 中的字符是 Unicode 類型,因此每個字符佔據 4 個字節內存空間,但是在字符串中不一樣,字符串是 UTF-8 編碼,也就是字符串中的字符所佔的字節數是變化的 (1 - 4),這樣有助於大幅降低字符串所佔用的內存空間。
由於 UTF-8 是一種可變寬度的編碼格式,因此字符串中的每個 ASCII 字符都存儲在一個字節中,而其他字符可能佔用多個字節。因此,在這種格式中,字符串字節的索引並不總是與有效的 Unicode 標量值相關。
字符串String
都沒有 index 的索引操作,如果想更方便地修改一個String
類型中的特定字節,則需要將其轉換爲vec<u8>
:
Rust 在語言級別,只有一種字符串類型:str
,它通常是以引用類型出現 &str
,也就是字符串切片。雖然語言級別只有上述的 str
類型,但是在標準庫裏,還有多種不同用途的字符串類型,其中使用最廣的即是 String
類型。
OsString
& &OsStr
OsString and OsStr are useful when you need to transfer strings to and from the operating system itself, or when capturing the output of external commands. Conversions between OsString, OsStr and Rust strings work similarly to those for CString and CStr.
顧名思義,這個是系統專用的合法字符串。
On Unix systems, strings are often arbitrary sequences of non-zero bytes, in many cases interpreted as UTF-8.
On Windows, strings are often arbitrary sequences of non-zero 16-bit values, interpreted as UTF-16 when it is valid to do so.
因爲行爲和系統有關,所以有系統相關的 Trait,比如std::os::unix::ffi::OsStrExt
。
OsString
是一種字符串類型,可以表示自有的、可變的平臺本機字符串,但可以低代價地與 Rust 字符串相互轉換。
這種類型的需求源於以下事實:
-
在 Unix 系統上,字符串通常是非零字節的任意序列,在許多情況下被解釋爲 UTF-8。
-
在 Windows 上,字符串通常是非零 16 位值的任意序列,在有效時解釋爲 UTF-16。
-
在 Rust 中,字符串總是有效的 UTF-8,其中可能包含零。
OsString
和[OsStr]
通過同時表示 Rust 和平臺本機字符串值,特別是允許將 Rust 字符串轉換爲 “OS” 字符串(如果可能的話),從而彌補了這一差距。這樣做的結果是OsString
實例不是 NUL 終止的;爲了傳遞到例如 Unix 系統調用,您應該創建一個CStr
。
OsString
與 &OsStr
的關係,與 String
和 &str
的關係一樣:每對中的前一個字符串都是擁有的字符串;後者是借來的引用數據。
注意,OsString
和 [OsStr]
內部不一定以平臺固有的形式保存字符串;在 Unix 上,字符串存儲爲 8 位值序列,而在 Windows 上,字符串是基於 16 位值的,正如前面所討論的,字符串實際上也存儲爲 8 位值序列,用一種不太嚴格的 UTF-8 變體編碼。這有助於瞭解處理容量和長度值的時間。
CString
& &Cstr
CString and CStr are useful when you need to transfer UTF-8 strings to and from languages with a C ABI, like Python.
顧名思義是和 C 接口交互的時候使用的類型:
CString
與 &CStr
的關係就像 String
和 &str
的關係一樣:CString
、String
自身擁有字符串數據,而 &CStr
、&str
只是借用數據而已。
PathBuf
& &Path
pub struct PathBuf {
inner: OsString,
}
Vec<u8>
& &[u8]
Rust 中字符串類型常用轉換
看一段簡單的代碼:
pub fn main() {
let s: String = String::from("HELLO");
let a: &str = &s;
let b: &str = &s[1..3];
let c = "beaf";
println!("a: {}, len: {}", a, a.len());
println!("b: {}, len: {}", b, b.len());
println!("c: {}, len: {}", c, c.len());
}
String
擁有所有內存相關的操作,可以對字符串做很多的處理, &str
包含長度,可以使用&str
獲取到String
中的任意一段的內容
-
&str
: 指針 + 長度。通常這種都叫做胖指針,胖指針一般有兩部分組成:指向 bytes 的指針和長度 -
String
: 指針 + 容器容量 + 長度。String
其實就是一個Vec
,擁有所有內存相關的操作,可以對字符串做很多的處理
從String
的源碼可以看到他的結構如下,看起來相當的簡單:
#[derive(PartialOrd, Eq, Ord)]
#[cfg_attr(not(test), rustc_diagnostic_item = "String")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
}
細究的話,Rust 中的字符串**String
,遠比想象中的複雜,如下圖所示:**
圖片來源於 RustTalk
注:附上內存容器類清單 Rust Memory Container Cheat-sheet
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/VurdZxRH4i9aCa5ue50r9w