11-Trait

Trait — The Rust Reference

译文 · 基于 The Rust Reference

原文链接: https://doc.rust-lang.org/reference/items/traits.html

r[items.traits]

Trait

r[items.traits.syntax]

Trait ->
    `unsafe`? `trait` IDENTIFIER GenericParams? ( `:` Bounds? )? WhereClause?
    `{`
        InnerAttribute*
        AssociatedItem*
    `}`

r[items.traits.intro] trait 描述类型可以实现的抽象接口。该接口由关联项组成,关联项有三种:

r[items.traits.namespace] trait 声明在其所在模块或块的类型命名空间中定义一个 trait。

r[items.traits.associated-item-namespaces] 关联项作为该 trait 的成员定义在各自的命名空间中。关联类型定义在类型命名空间中。关联常量和关联函数定义在值命名空间中。

r[items.traits.self-param] 所有 trait 都定义一个隐式类型参数 Self,指“正在实现此接口的类型”。trait 也可以包含额外的类型参数。这些类型参数(包括 Self)可以像往常一样被其他 trait 等约束。

r[items.traits.impls] trait 通过单独的实现为具体类型实现。

r[items.traits.associated-item-decls] trait 函数可以用分号替换函数体从而省略函数体。这表示实现必须定义该函数。若 trait 函数定义了函数体,则该定义作为任何未覆盖它的实现的默认实现。类似地,关联常量可以省略等号和表达式,以表示实现必须定义常量值。关联类型永远不能定义类型,类型只能在实现中指定。

1
2
3
4
5
6
7
8
// 带定义和不带定义的关联 trait 项示例。
trait Example {
    const CONST_NO_DEFAULT: i32;
    const CONST_WITH_DEFAULT: i32 = 99;
    type TypeNoDefault;
    fn method_without_default(&self);
    fn method_with_default(&self) {}
}

r[items.traits.const-fn] trait 函数不允许是 const。

r[items.traits.bounds]

Trait 约束

泛型项可以将其 trait 用作类型参数上的约束。

r[items.traits.generic]

泛型 trait

可以为 trait 指定类型参数以使其成为泛型。它们出现在 trait 名之后,使用与泛型函数相同的语法。

1
2
3
4
5
trait Seq<T> {
    fn len(&self) -> u32;
    fn elt_at(&self, n: u32) -> T;
    fn iter<F>(&self, f: F) where F: Fn(T);
}

r[items.traits.dyn-compatible]

Dyn 兼容性

r[items.traits.dyn-compatible.intro] dyn 兼容的 trait 可以成为 trait 对象的基 trait。若 trait 具有下列性质,则它是 dyn 兼容的:

r[items.traits.dyn-compatible.supertraits]

r[items.traits.dyn-compatible.sized]

  • Sized 不得是超 trait。换句话说,它不得要求 Self: Sized。

r[items.traits.dyn-compatible.associated-consts]

  • 不得有任何关联常量。

r[items.traits.dyn-compatible.associated-types]

  • 不得有任何带泛型的关联类型。

r[items.traits.dyn-compatible.associated-functions]

  • 所有关联函数必须要么可从 trait 对象分发,要么被显式标为不可分发:
    • 可分发函数必须:
      • 没有任何类型参数(不过允许生命周期参数)。
      • 是一个除接收者类型外不使用 Self 的方法。
      • 具有下列类型之一的接收者:
      • 没有不透明返回类型;也就是说,
        • 不是 async fn(它具有隐藏的 Future 类型)。
        • 没有返回位置的 impl Trait 类型(fn example(&self) -> impl Trait)。
      • 没有 where Self: Sized 约束(接收者类型为 Self(即 self)隐含这一点)。
      • 没有 C 可变参数(_: ...)。
    • 显式不可分发的函数要求:
      • 具有 where Self: Sized 约束(接收者类型为 Self(即 self)隐含这一点)。

r[items.traits.dyn-compatible.async-traits]

  • [AsyncFn]、[AsyncFnMut] 和 [AsyncFnOnce] trait 不是 dyn 兼容的。

注意 这一概念以前称为对象安全。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
## use std::rc::Rc;
## use std::sync::Arc;
## use std::pin::Pin;
// dyn 兼容方法的例子。
trait TraitMethods {
    fn by_ref(self: &Self) {}
    fn by_ref_mut(self: &mut Self) {}
    fn by_box(self: Box<Self>) {}
    fn by_rc(self: Rc<Self>) {}
    fn by_arc(self: Arc<Self>) {}
    fn by_pin(self: Pin<&Self>) {}
    fn with_lifetime<'a>(self: &'a Self) {}
    fn nested_pin(self: Pin<Arc<Self>>) {}
}
## struct S;
## impl TraitMethods for S {}
## let t: Box<dyn TraitMethods> = Box::new(S);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 此 trait 是 dyn 兼容的,但这些方法不能在 trait 对象上分发。
trait NonDispatchable {
    // 非方法不能被分发。
    fn foo() where Self: Sized {}
    // Self 类型直到运行时才知道。
    fn returns(&self) -> Self where Self: Sized;
    // `other` 可能是接收者的另一种具体类型。
    fn param(&self, other: Self) where Self: Sized {}
    // 泛型与 vtable 不兼容。
    fn typed<T>(&self, x: T) where Self: Sized {}
}

struct S;
impl NonDispatchable for S {
    fn returns(&self) -> Self where Self: Sized { S }
}
let obj: Box<dyn NonDispatchable> = Box::new(S);
obj.returns(); // 错误:不能用 Self 返回类型调用
obj.param(S);  // 错误:不能用 Self 参数调用
obj.typed(1);  // 错误:不能用泛型类型调用
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
## use std::rc::Rc;
// dyn 不兼容 trait 的例子。
trait DynIncompatible {
    const CONST: i32 = 1;  // 错误:不能有关联常量

    fn foo() {}  // 错误:没有 Sized 的关联函数
    fn returns(&self) -> Self; // 错误:返回类型中有 Self
    fn typed<T>(&self, x: T) {} // 错误:有泛型类型参数
    fn nested(self: Rc<Box<Self>>) {} // 错误:嵌套接收者不能被分发
}

struct S;
impl DynIncompatible for S {
    fn returns(&self) -> Self { S }
}
let obj: Box<dyn DynIncompatible> = Box::new(S); // 错误
1
2
3
4
5
6
// `Self: Sized` 的 trait 是 dyn 不兼容的。
trait TraitWithSize where Self: Sized {}

struct S;
impl TraitWithSize for S {}
let obj: Box<dyn TraitWithSize> = Box::new(S); // 错误
1
2
3
4
5
6
7
8
// 若 `Self` 是类型实参,则 dyn 不兼容。
trait Super<A> {}
trait WithSelf: Super<Self> where Self: Sized {}

struct S;
impl<A> Super<A> for S {}
impl WithSelf for S {}
let obj: Box<dyn WithSelf> = Box::new(S); // 错误:不能使用 `Self` 类型参数

r[items.traits.supertraits]

超 trait

r[items.traits.supertraits.intro] 超 trait(supertrait)是类型要实现某个特定 trait 时所必须实现的 trait。此外,任何被某个 trait 约束的泛型或 trait 对象都可以访问其超 trait 的关联项。

r[items.traits.supertraits.decl] 超 trait 通过 trait 的 Self 类型上的 trait 约束声明,并传递地包含那些 trait 约束中所声明 trait 的超 trait。trait 成为其自身的超 trait 是错误的。

r[items.traits.supertraits.subtrait] 具有超 trait 的 trait 称为其超 trait 的 子 trait(subtrait)。

下面是一个将 Shape 声明为 Circle 的超 trait 的例子。

1
2
trait Shape { fn area(&self) -> f64; }
trait Circle: Shape { fn radius(&self) -> f64; }

下面是同一个例子,只不过使用了 where 子句。

1
2
trait Shape { fn area(&self) -> f64; }
trait Circle where Self: Shape { fn radius(&self) -> f64; }

下一个例子使用来自 Shape 的 area 函数为 radius 给出默认实现。

1
2
3
4
5
6
7
8
9
## trait Shape { fn area(&self) -> f64; }
trait Circle where Self: Shape {
    fn radius(&self) -> f64 {
        // A = pi * r^2
        // 因此代数上,
        // r = sqrt(A / pi)
        (self.area() / std::f64::consts::PI).sqrt()
    }
}

下一个例子在泛型参数上调用超 trait 方法。

1
2
3
4
5
6
7
## trait Shape { fn area(&self) -> f64; }
## trait Circle: Shape { fn radius(&self) -> f64; }
fn print_area_and_radius<C: Circle>(c: C) {
    // 这里我们调用 `Circle` 的超 trait `Shape` 中的 area 方法。
    println!("Area: {}", c.area());
    println!("Radius: {}", c.radius());
}

类似地,这里是一个在 trait 对象上调用超 trait 方法的例子。

1
2
3
4
5
6
7
8
## trait Shape { fn area(&self) -> f64; }
## trait Circle: Shape { fn radius(&self) -> f64; }
## struct UnitCircle;
## impl Shape for UnitCircle { fn area(&self) -> f64 { std::f64::consts::PI } }
## impl Circle for UnitCircle { fn radius(&self) -> f64 { 1.0 } }
## let circle = UnitCircle;
let circle = Box::new(circle) as Box<dyn Circle>;
let nonsense = circle.radius() * circle.area();

r[items.traits.safety]

不安全 trait

r[items.traits.safety.intro] 以 unsafe 关键字开头的 trait 项表明实现该 trait 可能是不安全的。使用正确实现的不安全 trait 是安全的。trait 实现也必须以 unsafe 关键字开头。

Sync 和 Send 是不安全 trait 的例子。

r[items.traits.params]

参数模式

r[items.traits.params.patterns-no-body] 没有函数体的关联函数中的参数只允许 [IDENTIFIER] 或 _ 通配符模式,以及 [SelfParam] 所允许的形式。目前允许 mut [IDENTIFIER],但它已弃用,将来会成为硬错误。

1
2
3
4
trait T {
    fn f1(&self);
    fn f2(x: Self, _: i32);
}
1
2
3
trait T {
    fn f2(&x: &i32); // 错误:没有函数体的函数中不允许模式
}

r[items.traits.params.patterns-with-body] 有函数体的关联函数中的参数只允许不可反驳模式。

1
2
3
trait T {
    fn f1((a, b): (i32, i32)) {} // 可以:不可反驳
}
1
2
3
4
trait T {
    fn f1(123: i32) {} // 错误:模式可反驳
    fn f2(Some(x): Option<i32>) {} // 错误:模式可反驳
}

r[items.traits.params.pattern-required.edition2018]

[!EDITION-2018] 在 2018 edition 之前,关联函数参数的模式是可选的:

1
2
3
4
// 2015 Edition
trait T {
    fn f(i32); // 可以:不要求参数标识符
}

从 2018 edition 开始,模式不再是可选的。

r[items.traits.params.restriction-patterns.edition2018]

[!EDITION-2018] 在 2018 edition 之前,有函数体的关联函数中的参数仅限于下列种类的模式:

  • [IDENTIFIER]
  • mut [IDENTIFIER]
  • _
  • & [IDENTIFIER]
  • && [IDENTIFIER]
1
2
3
4
// 2015 Edition
trait T {
    fn f1((a, b): (i32, i32)) {} // 错误:不允许该模式
}

从 2018 开始,如 [items.traits.params.patterns-with-body] 所述,允许所有不可反驳模式。

r[items.traits.associated-visibility]

项可见性

r[items.traits.associated-visibility.intro] trait 项在语法上允许 [Visibility] 注解,但在验证 trait 时会被拒绝。这使项可以在不同使用上下文中以统一语法被解析。例如,可以为 trait 项使用空的 vis 宏片段说明符,而该宏规则还可以用在允许可见性的其他场合。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
macro_rules! create_method {
    ($vis:vis $name:ident) => {
        $vis fn $name(&self) {}
    };
}

trait T1 {
    // 允许空的 `vis`。
    create_method! { method_of_t1 }
}

struct S;

impl S {
    // 这里允许可见性。
    create_method! { pub method_of_s }
}

impl T1 for S {}

fn main() {
    let s = S;
    s.method_of_t1();
    s.method_of_s();
}
最后修改 August 21, 2026: 更新 (76fc81a2e)