为通用调用者实现特征?

Implement Trait for generic caller?

我刚刚读了 this article about generics and Traits 中的 Rust by Example,他们似乎在通用调用者上实现了一个 Trait。查看他们的文章以获取完整示例,但这是一个最小的工作示例:

struct Example;

trait Foo {
  fn print_foo(&self);
}

impl<T> Foo for T {
  fn print_foo(&self) {
    println!("foo");
  }
}

fn main() {
  let example = Example;
  example.print_foo();
}

此示例有效并打印 foo。这是如何运作的?对于上下文,我阅读了完整的 Rust 书,直到上述文章才看到这一点。像这样的通用实现到底是如何工作的?编译器如何知道将 print_fooExample 相关联? impl 的范围如何?我可以有板条箱范围的通用实现吗?

How exactly does a generic implementation like this work?

您或多或少可以将泛型视为惰性代码生成:impl<T> Foo for T 表示“对于 every¹ 具体类型 T,如果需要为 T 实现 Foo,请使用此函数创建一个。”

How does the compiler know to associate print_foo with Example?

当编译器看到方法调用时,这里.print_foo(),

  • 它首先寻找匹配的内在实现,impl Foo { fn print_foo(&self) {...} }。在这种情况下找不到。
  • 它查看当前范围内可见的所有特征(已定义或used)以查看它们是否定义了一个名为[=14的方法=].
  • 它检查 Example 是否实现了这些特征中的任何一个。 Example 实现了 Foo,因为 所有东西 (未确定大小的类型除外)都实现了 Foo,因此使用了该特性。

这些规则在 Rust 参考的 Method-call expressions 部分中描述。

How is this impl scoped? Could I have crate-scoped generic implementations?

特性实现 未限定范围。它们实际上无处不在,无论什么可能被带入当前范围。 (trait implementation coherence 规则旨在确保找到哪些实现永远不会取决于当前 crate 的依赖项中有哪些 crate,即编译器编译了哪些代码。)

然而,traits 是有作用域的:trait 方法永远不会被找到,除非 trait 被 use 引入作用域或者在同一个模块中定义它。

在您的特定情况下,impl<T> Foo for T 意味着 不可能为特征编写任何其他实现 ¹ — 没有“板条箱”之类的东西-范围内的通用实现”。


¹ <T> 并不完全意味着“每种类型”。它的意思是“每个大小类型”,因为大多数通用代码无法处理动态大小/“未大小”类型,如dyn Foo[i32],所以它是一个有用的默认限制。如果您改写 <T: ?Sized>,那么泛型确实覆盖了所有可能的类型。