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

Dre*_*rew 18 generics rust

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

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
}
Run Code Online (Sandbox Code Playgroud)

我想把generate它放到我的矢量中:

impl<A: Generator, B> Baz<A, B> {
    fn addFoo(&mut self) {
        self.vec.push(self.generator.generate());
    }
}
Run Code Online (Sandbox Code Playgroud)

嗯,哦!编译错误:

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`
Run Code Online (Sandbox Code Playgroud)

很公平,我必须说明的编译器B是一样的A::Foo; 让我们尝试where:

impl<A: Generator, B> Baz<A, B>
where
    A::Foo = B,
{
Run Code Online (Sandbox Code Playgroud)

这没有帮助:

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

嗯,不等于.也许我可以用冒号操作符代替这个?

impl<A: Generator, B> Baz<A, B>
where
    B: A::Foo,
{
Run Code Online (Sandbox Code Playgroud)
error[E0405]: cannot find trait `Foo` in `A`
  --> src/main.rs:16:11
   |
16 |     B: A::Foo,
   |           ^^^ not found in `A`
Run Code Online (Sandbox Code Playgroud)

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

impl<A: Generator, B> Baz<A, B>
where
    B: Generator::Foo,
{
Run Code Online (Sandbox Code Playgroud)
error[E0404]: expected trait, found associated type `Generator::Foo`
  --> src/main.rs:16:8
   |
16 |     B: Generator::Foo,
   |        ^^^^^^^^^^^^^^ not a trait
Run Code Online (Sandbox Code Playgroud)

好的工作,编译器 - 它不是特性; 它是一个关联类型,但这并没有告诉我如何编写匹配它的where子句.

swi*_*ard 23

我必须向编译器解释与之B相同的内容A::Foo

它有一个特殊的语法:

impl<A, B> Baz<A, B>
where
    A: Generator<Foo = B>,
{
    fn add_foo(&mut self) {
        self.vec.push(self.generator.generate());
    }
}
Run Code Online (Sandbox Code Playgroud)


She*_*ter 13

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

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


oli*_*obk 6

您可以摆脱泛型参数B而不是约束B,直接传递A::Foo为第二个泛型参数Baz,但我不确定您的实际问题是否与您展示的简化示例匹配.

impl<A: Generator> Baz<A, A::Foo> {
    fn addFoo(&mut self)  {
        self.vec.push(self.generator.generate());
    }
}
Run Code Online (Sandbox Code Playgroud)