字符串字面量
let s = "hello";
变量s
属于字符串字面量,它们属于硬编码进程序的字符串值,属于不可变的类型。但并不是所有字符串的值都能够在编写代码时确定。
String类型
String
类型会在堆上分配到自己需要的存储空间,所以它能够处理在编译时未知大小的文本。
对于String
类型而言,为了支持一个可变、可增长的文本类型,我们需要在堆上分配一块在编译时未知大小的内存来存放数据。这同时也意味着:
- 我们使用的内存是操作系统在运行时动态分配出来的
- 当使用完
String
时,我们需要通过某种方式将这些内存归还给操作系统
let s: String = String::from("hello");let s2 = s;
String
对象的内存布局实际由3部分组成,如下图所示:一个指向存放字符串内容的指针(ptr
)、一个长度(len
)及一个容量(capacity
),这部分的数据存储在栈上。
将变量s
赋值给s2
,其实是栈上将变量的所有权转移给了s2
。RUST
也不需要在s
离开作用域后做任何清理,试图在s2
创建完毕后使用s
会导致编译错误。
浅拷贝
假如你在其它语言中接触过浅拷贝(shallow copy
)和深拷贝(deep copy
)这两个术语,那么你也许会将这里的复制行为视作浅拷贝。但由于RUST
同时使第一个变量无效了,所以我们使用了新的术语移动(move
)来描述这一行为,而不再使用浅拷贝。
RUST
的设计原则:RUST
永远不会自动地创建数据的深度拷贝。因此在RUST
中,任何自动的赋值操作都可以被视为高效的。
clone
当你确实需要去深拷贝String
堆上的数据,而不仅仅是栈数据时,就可以使用一个名为clone
的方法。
let s: String = String::from("hello");let s2 = s.clone();
字符串切片
字符串切片是指String
对象中某个连续部分的引用,它的使用方式如下:
let s: String = String::from("hello");let hello = &s[0..5];
我们在一对方括号中指定了切片的范围区间[start_index..end_index]
,其中的end_index
是切片终止位置的的下一个索引值。
切片数据结构在内部存储了指向其实位置的引用和一个描述切片长度的字段,这个切片长度就等于end_index-start_index
。