将泛型参数与 impl 中的关联类型匹配

Posted

技术标签:

【中文标题】将泛型参数与 impl 中的关联类型匹配【英文标题】:Matching a generic parameter to an associated type in an impl 【发布时间】:2015-03-30 12:00:39 【问题描述】:

我有一个具有关联类型和通用结构的特征::

trait Generator 
    type Foo;
    fn generate(&self) -> Self::Foo;


struct Baz<A, B>
where
    A: Generator,

    generator: A, // will be some struct implementing Generator, but the exact type will vary
    vec: Vec<B>,  // Each element will be A::Foo

我想generate 并将其放入我的向量中:

impl<A: Generator, B> Baz<A, B> 
    fn addFoo(&mut self) 
        self.vec.push(self.generator.generate());
    

呃-哦!编译错误:

error[E0308]: mismatched types
  --> src/main.rs:16:27
   |
16 |             self.vec.push(self.generator.generate());
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found associated type
   |
   = note: expected type `B`
              found type `<A as Generator>::Foo`

公平地说,我必须向编译器解释BA::Foo 相同;让我们试试where:

impl<A: Generator, B> Baz<A, B>
where
    A::Foo = B,

这没有帮助:

error: equality constraints are not yet supported in where clauses (#20041)
  --> src/main.rs:16:5
   |
16 |     A::Foo = B,
   |     ^^^^^^^^^^

嗯,不等于。也许我可以用冒号运算符来代替?

impl<A: Generator, B> Baz<A, B>
where
    B: A::Foo,

error[E0405]: cannot find trait `Foo` in `A`
  --> src/main.rs:16:11
   |
16 |     B: A::Foo,
   |           ^^^ not found in `A`

不,现在它在抱怨A。也许我应该说Generator

impl<A: Generator, B> Baz<A, B>
where
    B: Generator::Foo,

error[E0404]: expected trait, found associated type `Generator::Foo`
  --> src/main.rs:16:8
   |
16 |     B: Generator::Foo,
   |        ^^^^^^^^^^^^^^ not a trait

干得好,编译器——它不是特性;它是一个关联类型,但这并没有告诉我如何编写与其匹配的 where 子句。

【问题讨论】:

您确定需要生成子类型吗? 【参考方案1】:

我必须向编译器解释BA::Foo是一样的

它有一个特殊的语法:

impl<A, B> Baz<A, B>
where
    A: Generator<Foo = B>,

    fn add_foo(&mut self) 
        self.vec.push(self.generator.generate());
    

【讨论】:

我认为这是他所要求的答案,而不是他想要的答案。谢谢,我不知道这种语法。【参考方案2】:

诀窍是只有一个通用参数:

trait Generator 
    type Foo;
    fn generate(&self) -> Self::Foo;


struct Baz<G>
where
    G: Generator,

    generator: G,
    vec: Vec<G::Foo>,


impl<G> Baz<G>
where
    G: Generator,

    fn add_foo(&mut self) 
        self.vec.push(self.generator.generate());
    

由于向量将包含G::Foo,我们实际上可以这么说。

Rust 风格是snake_case,所以我更新了它并制作了类型参数G 来帮助读者。

【讨论】:

【参考方案3】:

您可以摆脱通用参数B 而不是约束B,而是直接将A::Foo 作为第二个通用参数传递给Baz,但我不确定您的实际问题是否与简化的问题相符你展示的例子。

impl<A: Generator> Baz<A, A::Foo> 
    fn addFoo(&mut self)  
        self.vec.push(self.generator.generate());
    

【讨论】:

以上是关于将泛型参数与 impl 中的关联类型匹配的主要内容,如果未能解决你的问题,请参考以下文章

泛型中的类型擦除

如何将泛型类型参数限制为 System.Enum [重复]

Java 将泛型类型与 Void 进行比较

将泛型与索引类型相结合

将泛型 T 的类型解析为 C# 中的特定接口

将泛型与可能是值或引用类型的 null 进行比较?