这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

Sized trait

Sized trait用于标记在编译时已知常量大小的类型。

1 - Sized trait的std文档

Sized trait的std文档

https://doc.rust-lang.org/std/marker/trait.Sized.html

pub trait Sized { }

在编译时已知常量大小的类型。

所有类型参数的隐含边界均为 Sized。如果不合适,可以使用特殊语法 ?Sized 删除此绑定。

struct Foo<T>(T);
struct Bar<T: ?Sized>(T);

// struct FooUse(Foo<[i32]>); // 错误:没有为 [i32] 实现大小调整
struct BarUse(Bar<[i32]>); // OK

一个例外是 trait 的隐式 Self 类型。 trait 没有隐式 Sized 绑定,因为它与 trait 对象 不兼容,根据定义,trait 需要与所有可能的实现者一起使用,因此可以为任意大小。

尽管 Rust 允许您将 Sized 绑定到 trait,但是以后您将无法使用它来形成 trait 对象:

trait Foo { }
trait Bar: Sized { }

struct Impl;
impl Foo for Impl { }
impl Bar for Impl { }

let x: &dyn Foo = &Impl;    // OK
// let y: &dyn Bar = &Impl; // 错误:无法将 trait `Bar` 创建成对象

备注:trait object的要求之一就是trait不能是Sized,这也可以作为禁止将某个trait用作trait object的方式

2 - Sized trait的源码

Sized trait的

https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs

#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented(
    message = "the size for values of type `{Self}` cannot be known at compilation time",
    label = "doesn't have a size known at compile-time"
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait]
pub trait Sized {
    // Empty.
}

3 - [Rust编程之道笔记]Sided trait

Rust编程之道一书 3.4.4 标签trait

Sized trait 非常重要,编译期用它来识别在编译期确定大小的类型。

#[lang = "sized"]
pub trait Sized {
    // Empty.
}

Sized trait 是空 trait,仅仅作为标签 trait 供编译期使用。真正起"打标签"作用的是属性 #[lang = "sized"]。该属性lang表示Sized trait供rust语言本身使用,声明为 “sized”,称为语言项(Lang Item)。

rust语言中大部分类型都是默认 Sized ,如果需要使用动态大小类型,则需要改为 <T: ?Sized> 限定。

struct Foo<T>(T);
struct Bar<T: ?Sized>(T);

Sized, Unsize和 ?Sized的关系

  • Sized 标记的是在编译期可确定大小的类型

  • Unsized 标记的是动态大小类型,在编译期无法确定其大小

    目前rust中的动态类型有 trait 和 [T]

    其中 [T] 代表一定数量的T在内存中的一次排列,但不知道具体的数量,所以大小是未知的。

  • ?Sized 标记的类型包含了 Sized 和 Unsized 所标识的两种类型。

    所以泛型结构体 struct Bar<T: ?Sized>(T); 支持编译期可确定大小类型和动态大小类型两种类型。

动态大小类型的限制规则

  • 只可以通过胖指针来操作 Unsize 类型,如 &[T] 或者 &trait
  • 变量,参数和枚举变量不能使用动态大小类型
  • 结构体中只有最有一个字段可以使用动态大小类型,其他字段不可以使用