简体   繁体   English

Rust 如何使用循环特征边界编译这个示例?

[英]How does Rust compile this example with cyclic trait bounds?

I'm having trouble understanding how the following example, distilled from this code , compiles:我无法理解从这段代码中提取的以下示例如何编译:

trait A: B {}
trait B {}
impl<T> B for T where T: A {}

struct Foo;
impl A for Foo {}

fn main() {}

My current understanding is that我目前的理解是

Supertraits are traits that are required to be implemented for a type to implement a specific trait. Supertraits 是为实现特定 trait 的类型需要实现的特征。

  • impl<T> B for T where T:A implements B for any type with the trait A . impl<T> B for T where T:A为具有特征 A 的任何类型实现 B 。

I expect impl A for Foo to fail because before A is implemented for Foo, the blanket implementation can't implement B for Foo, which is required.我希望impl A for Foo会失败,因为在为 Foo 实现 A 之前,一揽子实现不能为 Foo 实现 B,这是必需的。

My most plausible model for what rustc does while compiling the snippet is as follows:对于 rustc 在编译代码段时所做的工作,我最合理的模型如下:

  • implement A for Foo, deferring the check that Foo implements B to a later stage为 Foo 实现 A,将 Foo 实现 B 的检查推迟到稍后阶段
  • implement B for Foo with the blanket implementation, since Foo now implements A用一揽子实现为 Foo 实现 B,因为 Foo 现在实现了 A
  • check that Foo implements B as required by the trait bound A: B检查 Foo 是否按照 trait bound A: B

Is this in some way close to the truth?这在某种程度上接近事实吗? Is there any documentation I missed explaining the order in which implementations are processed?是否有任何我错过的文档来解释处理实现的顺序?

rustc doesn't work "in order". rustc 不能“按顺序”工作。 Rather, we first register all impls and then type-check each impl with no particular order.相反,我们首先注册所有 impl,然后对每个 impl 进行类型检查,没有特定的顺序。 The idea is that we collect a list of obligations (of various kinds - one of them is a trait bound), and then we match them against impl s (not just; this is only one way to resolve an obligation, but this is what relevant here).这个想法是我们收集义务列表(各种类型 - 其中一个是 trait bound),然后我们将它们与impl匹配(不仅仅是;这只是解决义务的一种方法,但这就是此处相关)。 Each obligation can create another, recursive obligations and we elaborate them until there are no more.每个义务都可以创建另一个递归义务,我们会详细说明它们,直到不再有。

The way it currently works is that when we check an impl Trait for Type , we add an obligation Type: Trait .它目前的工作方式是,当我们检查impl Trait for Type ,我们添加了一个义务Type: Trait This might seem silly, but we later elaborate it further until all required bounds are met.这可能看起来很愚蠢,但我们稍后会进一步详细说明,直到满足所有要求的界限。

So let's say we're currently checking impl<T> B for T where T: A .因此,假设我们目前正在检查impl<T> B for T where T: A We add one obligation, T: B , and match it against impl B for T .我们添加一项义务T: B ,并将其与impl B for T匹配。 There is nothing to elaborate further, so we finish successfully.没有什么可以进一步阐述的,所以我们成功地完成了。

We then check impl A for Foo , and add an obligation Foo: A .然后我们检查impl A for Foo ,并添加一个义务Foo: A Since the trait A requires Self: B , we add another obligation Foo: B .由于特征A需要Self: B ,我们添加另一个义务Foo: B Then we start matching obligations: the first obligation, Foo: A , is matched by the currently processed impl with no additional obligations.然后我们开始匹配义务:第一个义务Foo: A与当前处理的impl匹配,没有额外的义务。 The second obligation, Foo: B , is matched against impl<T> B for T where T: A .第二个义务Foo: Bimpl<T> B for T where T: A匹配。 This has a new obligate - T: A or Foo: A - so we try to match that.这有一个新的义务 - T: AFoo: A - 所以我们尝试匹配它。 We successfully match that against impl A for Foo , with no additional obligations.我们成功地impl A for Foo匹配,没有额外的义务。

An interesting implication of the above is that if we change the second impl to the following:上面的一个有趣的含义是,如果我们将第二个impl更改为以下内容:

impl A for Foo where Foo: B {}

Then this no longer compile with a "overflow evaluating the requirement Foo: A " error ( playground ), even though it is essentially the same, because now to prove that Foo: A rustc needs to prove that Foo: B and again that Foo: A , while previously it just registered an obligation for Foo: B and not proved it immediately.然后这不再与“评估要求Foo: A的溢出”错误( 操场)编译,即使它本质上是相同的,因为现在要证明Foo: A rustc 需要证明Foo: B并再次证明Foo: A ,而之前它只是为Foo: B注册了一项义务,并没有立即证明它。

Note: The above is an over-simplification: for example, there is also a cache, and well-formed obligations, and much more.注意:以上是过度简化:例如,还有一个缓存,以及格式良好的义务,等等。 But the general principle is the same.但一般原理是一样的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM