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 字符,則可以考慮使用如下類型:

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 字符串相互轉換。

這種類型的需求源於以下事實:

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 的關係一樣:CStringString 自身擁有字符串數據,而 &CStr&str只是借用數據而已。

PathBuf & &Path

 pub struct PathBuf {
   inner: OsString,
 }

Vec<u8> & &[u8]

Rust 中字符串類型常用轉換

Tzbio3

看一段簡單的代碼:

 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中的任意一段的內容

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