rust 中 str 與 String; &str &String

Aitozi發表於2023-05-16

String

String 型別的資料和基本型別不同,基本型別的長度是固定的,所以可以在棧上分配,而String型別是變長的,所以需要在堆上分配,所以String 型別實際上是一個指向堆的指標。他的結構和Vec很類似。從他的宣告看也是一個u8的Vec

pub struct String {
    vec: Vec<u8>,
}

看這樣一個定義: Programming Rust 2nd Edition 第三章
image.png
image.png
透過字面量宣告的是一個 &str。透過to_string 方法轉成一個String型別。
如果是一個字面量,那實際上是程式中預先分配好的只讀記憶體,如上面的poodles。
String型別是一個 **擁有堆上資料所有權 **的指標,包含了capacity 和 長度
&str 是堆上資料的一個 切片,並不擁有資料。當執行to_string 的時候,會將資料複製到堆上
image.png

str和&str

下面定義四種不同的型別
image.png

image.png
這裡會有一個編譯報錯,提示 str 型別在編譯期無法知道其大小。
上面說過 str 實際上是 堆上資料的一個切片,所以其型別 應該是 [u8]如下面的一個 Vec<i32> 的一個切片的型別就是 [i32]
而由於slice可以是任意長度,所以slice型別不可以直接儲存在變數中(不確定長度的資料沒法儲存在棧上)。所以slice的資料都是以reference&的形式在使用。
以vec為例
image.png
image.png
指向一個slice的ref是2位元組長度,第一個位元組儲存了slice第一個元素的指標,第二個位元組儲存了slice的長度。
所以str型別是String的切片型別一般無法直接互動,&str是切片型別的引用。
另外對於 str 型別,雖然不能直接互動,但是可以在上面定義方法,比如上面提到的to_string方法
image.png

&String

通常來說 String 在棧上分配,資料儲存在堆上,而&String是指向 String 的引用。&String 有點類似於&str 不過 &str直接指向了 切片的第一個元素,而&String首先指向了String,再指向heap,感覺開銷會更大一些? 不過可能編譯期會處理掉這個開銷。總之看起來 &String沒有什麼使用需求。

再對比下Java 中的String,實際Java的String物件和基本物件不同,也是一個引用所以可以儲存在棧上,而String內部儲存資料的是一個byte[]陣列。Java String物件本身也是不可變的,修改字串會重寫在堆上分配記憶體重寫新的。
Java中除了基本型別,其他型別都是引用型別,遮蔽了內部這些細節,而rust中對這些做了區分,交給使用者來進行處理。

除了String之外,rust中的字串相關的型別還有
image.png

參考

https://www.reddit.com/r/rust/comments/fgpdb0/trying_to_understand_str_vs_str_t_vs_t_osstr_vs/

相關文章