String 型別的資料和基本型別不同,基本型別的長度是固定的,所以可以在棧上分配,而String型別是變長的,所以需要在堆上分配,所以String 型別實際上是一個指向堆的指標。他的結構和Vec很類似。從他的宣告看也是一個u8的Vec
pub struct String {
vec: Vec<u8>,
}
看這樣一個定義: Programming Rust 2nd Edition 第三章
通過字面量宣告的是一個 &str
。通過to_string 方法轉成一個String型別。
如果是一個字面量,那實際上是程式中預先分配好的唯讀記憶體,如上面的poodles。
String型別是一個 **擁有堆上資料所有權 **的指標,包含了capacity 和 長度
&str 是堆上資料的一個 切片,並不擁有資料。當執行to_string 的時候,會將資料拷貝到堆上
下面定義四種不同的型別
這裡會有一個編譯報錯,提示 str 型別在編譯期無法知道其大小。
上面說過 str 實際上是 堆上資料的一個切片,所以其型別 應該是 [u8]
如下面的一個 Vec<i32>
的一個切片的型別就是 [i32]
而由於slice可以是任意長度,所以slice型別不可以直接儲存在變數中(不確定長度的資料沒法儲存在棧上)。所以slice的資料都是以reference&
的形式在使用。
以vec為例
指向一個slice的ref是2位元組長度,第一個位元組儲存了slice第一個元素的指標,第二個位元組儲存了slice的長度。
所以str型別是String的切片型別一般無法直接互動,&str
是切片型別的參照。
另外對於 str 型別,雖然不能直接互動,但是可以在上面定義方法,比如上面提到的to_string
方法
通常來說 String 在棧上分配,資料儲存在堆上,而&String
是指向 String 的參照。&String
有點類似於&str
不過 &str
直接指向了 切片的第一個元素,而&String
首先指向了String,再指向heap,感覺開銷會更大一些? 不過可能編譯期會處理掉這個開銷。總之看起來 &String
沒有什麼使用需求。
再對比下Java 中的String,實際Java的String物件和基本物件不同,也是一個參照所以可以儲存在棧上,而String內部儲存資料的是一個byte[]
陣列。Java String物件本身也是不可變的,修改字串會重寫在堆上分配記憶體重寫新的。
Java中除了基本型別,其他型別都是參照型別,遮蔽了內部這些細節,而rust中對這些做了區分,交給使用者來進行處理。
除了String之外,rust中的字串相關的型別還有
https://www.reddit.com/r/rust/comments/fgpdb0/trying_to_understand_str_vs_str_t_vs_t_osstr_vs/
本文來自部落格園,作者:Aitozi,轉載請註明原文連結:https://www.cnblogs.com/Aitozi/p/17406915.html