24、String slices(字符串切片)

String slices(字符串切片)

在前面几个章节的代码中,我们用到了很多的字符串字面量。他们后面总是调用.to_string()into()。现在深入研究一下原因。

字符串字面量

我们可以通过将原始文本括在双引号里面来定义字符串文字:

let s = "Hello, world!";

s的类型就是&str,这是对字符串切片的引用。

内存布局

&strString是不同的类型,他们之间不可以互换。回想一下之前学习过的String的内存布局,如果我们运行下面的代码:

let mut s = String::with_capacity(5);
s.push_str("Hello");

我们将会在内存中得到这个场景:

String类型内存布局

 

我们还研究过&String的内存布局:

&String类型内存布局

 

&String指针指向了存储String的元数据的内存地址。

如果我们顺着这个指针找,我们可以找到由堆分配的内存。特别是,我们到达的是字符串的第一个字节H

如果我们想要获取一个表示s子字符串的类型呢?比如Hello里面的ello

字符串切片

&str 是对字符串的视图,即指向存储在其他位置的一组 UTF-8 字节的引用。例如,你可以像这样从 String 创建一个 &str:

let mut s = String::with_capacity(5);
s.push_str("Hello");
// Create a string slice reference from the `String`, 
// skipping the first byte.
let slice: &str = &s[1..];

内存布局如图所示:

&s[1..]的内存布局

silce(切片)在栈上存储两条信息

  • 指向切片第一个字节的指针
  • 切片的长度

 

切片不拥有数据,它只是指向它:切片是对字符串堆分配数据的引用。

 

当切片dropped时,堆分配的数据不会被释放,因为它依然被s所有。

这就是为什么切片没有capacity字段的原因:它不拥有数据,所以不需要知道为数据分配了多少的空间,它只关心它引用的数据。

&str和&String的比较

根据经验,在引用文本数据时,使用&str而不是&String

&str更加灵活,在Rust代码中通常被认为更惯用。

如果一个方法返回一个&String,我们就保证在某个地方存在堆分配的UTF-8文本,与我们返回的引用完全匹配。

但是如果我们这个方法返回的是一个&str,我们就更加的自由:我们只需要说明在某个地方有一堆文本数据,其中的一个子集与我们需要的匹配,因此我们需要返回它的引用。

阅读剩余
THE END