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/