Sized

即便研究过解引用强制转换 (deref coercion),&str 仍然有一些没暴露出来的细节。
基于我们前面关于内存布局的讨论, 本来合理的预期是 &str 在栈上表示为单个 usize——一个指针。但事实并非如此。&str 在指针旁还存了一些元数据 (metadata):它指向的切片的长度。回到前一节的例子:

let mut s = String::with_capacity(5);
s.push_str("Hello");
// 从 `String` 创建一个字符串切片引用,
// 跳过第一个字节。
let slice: &str = &s[1..];

在内存里,我们得到:

                    s                              slice
      +---------+--------+----------+      +---------+--------+
Stack | pointer | length | capacity |      | pointer | length |
      |    |    |   5    |    5     |      |    |    |   4    |
      +----|----+--------+----------+      +----|----+--------+
           |        s                           |  
           |                                    |
           v                                    | 
         +---+---+---+---+---+                  |
Heap:    | H | e | l | l | o |                  |
         +---+---+---+---+---+                  |
               ^                                |
               |                                |
               +--------------------------------+

这是怎么回事?

动态尺寸类型 (Dynamically sized types)

str 是一种动态尺寸类型 (dynamically sized type, DST)
DST 的大小在编译期是未知的。每当你持有对 DST 的引用——例如 &str——它必须包含关于其所指数据的额外信息。这就是胖指针 (fat pointer)
&str 的情形下,它存储了它所指切片的长度。 我们会在课程后面看到更多 DST 的例子。

Sized 特质 (The Sized trait)

Rust 的 std 库定义了一个名为 Sized 的特质。

pub trait Sized {
    // 这是个空特质,没有任何方法要实现。
}

如果一个类型的大小在编译期已知,它就是 Sized 的。换句话说,它不是 DST。

标记特质 (Marker traits)

Sized 是你接触到的第一个标记特质 (marker trait)
标记特质不要求实现任何方法,也不定义任何行为。 它只用来标记 (mark) 一个类型具有某些性质。 然后编译器利用这个标记来启用某些行为或优化。

自动特质 (Auto traits)

特别地,Sized 也是一个自动特质 (auto trait)
你不需要显式实现它,编译器会根据类型的定义自动为你实现。

例子 (Examples)

到目前为止我们见过的所有类型都是 Sizedu32Stringbool 等等。

str,正如刚才所见,不是 Sized 的。
不过 &strSized 的!我们在编译期就知道它的大小:两个 usize,一个用于指针,一个用于长度。

原文链接:英文原文