# Rust中的Sizedness
_22 July 2020 · #rust · #sizedness_
**目录**
- [介绍](#介绍)
- [Sizedness(大小确定性)](#sizedness大小确定性)
- [`Sized` Trait](#sized-trait)
- [泛型中的`Sized`](#泛型中的sized)
- [不定大小类型(Unsized Types)](#不定大小类型unsized-types)
- [Slices(切片)](#slices切片)
- [Trait Objects(特性对象)](#trait-objects特性对象)
- [trait object的限制](#trait-object的限制)
- [不能将不定大小类型强转为trait object](#不能将不定大小类型强转为trait-object)
- [不能创建多特性对象](#不能创建多特性对象)
- [用户定义的不定大小类型](#用户定义的不定大小类型)
- [0大小类型](#0大小类型)
- [单元类型](#单元类型)
- [用户定义的单元大小结构](#用户定义的单元大小结构)
- [不可能类型(Never Type)](#不可能类型never-type)
- [用户定义的伪不可能类型](#用户定义的伪不可能类型)
- [PhantomData(伪数据)](#phantomdata伪数据)
- [总结](#总结)
- [讨论](#讨论)
- [进一步阅读](#进一步阅读)
- [通知](#通知)
## 介绍
大小确定性(Sizedness)在Rust的众多重要概念中是相对不引人注目的一个。它以隐晦的方式与众多其它语言特性互相作用,并且往往只以错误提示的形式让我们了解到它的存在,这个错误我们Rustacean大概常遇到,就是"_x doesn't have size known at compile time_"(_x没有确定的编译时大小_)。本文将介绍与Sizeness相关的各种语言特性,包括: 确定大小类型(sized types),不定大小类型(unsized types),以及0大小类型(zero-sized types),我们将探讨它们的使用场景,应用,痛点,以及在必要的时候如何绕过Sizeness带来的困扰。
名词解释:
| 名词 | 解释 |
|-|-|
| sizedness(大小确定性) | 表明特定类型有或没有确定的大小 |
| sized type(确定大小类型) | 编译时有确定大小的类型 |
| 1) unsized type(不定大小类型) _或_
2) DST | 动态大小类型,也就是说,该类型的大小不能在编译时确定 |
| ?sized type(未知大小类型) | 可能是sized type,也可能是unsized type |
| unsized coercion(不定大小强转) | 将一个确定大小类型强转为一个不定大小类型 |
| ZST | zero-sized type(0大小类型),即,该类型的大小为0字节 |
| width(宽度) | 一个度量单位,用于描述指针宽度 |
| 1) 瘦指针 _或_
2) 单width指针 | 大小为 _1 width_ 的指针 |
| 1) 胖指针 _or_
2) 双width指针 | 大小为 _2 widths_ 的指针|
| 1) 指针 _or_
2) 引用 | 指针,其具体 _width_ 会在相应的上下文中说明 |
| slice(切片) | 指向某个数组动态大小视图的双width指针 |
| (译者补充: trait object(特性对象)) | 实现某个trait的对象([dyn SomeTrait](https://github.com/mercury-2025/rust-blog/blob/master/posts/tour-of-rusts-standard-library-traits.md#trait-objects)) |
## Sizedness(大小确定性)
在Rust中,所谓的Sizedness是指一个类型的具体大小是否可以在编译时确定。确定类型大小之所以重要,是因为这样一来,才有可能为类型的实例在栈上分配相应的空间。确定大小类型(Sized types)可以使用传值或传引用的方式到处传递。同样的,如果一个类型的大小不能在编译时确定,我们就称它为不定大小类型(unsized type)或者DST,又或者叫它动态大小类型。因为不定大小类型不能放到栈上,所以它们只能以引用的形式传递。 下面是一部分 _确定大小类型_ 和 _不定大小类型_ 的例子:
```rust
use std::mem::size_of;
fn main() {
// 原始类型
assert_eq!(4, size_of::());
assert_eq!(8, size_of::());
// 元组
assert_eq!(8, size_of::<(i32,i32)>());
// 数组
assert_eq!(0, size_of::<[i32; 0]>());
assert_eq!(12, size_of::<[i32; 3]>());
struct Point {
x: i32,
y: i32,
}
// 结构体
assert_eq!(8, size_of::());
// 枚举
assert_eq!(8, size_of::