约束泛型关联类型的关联类型

Constraint associated type of a generic associated type

我有一个带有通用关联类型 (GAT) InstanceForBuilder<'a> 的类型 Builder。 我想编写一个函数 (build_with_42_for_bool<Builder>),将 Builder 限制为仅 Builder::InstanceForBuilder<'a>::InstanceProperty == bool(对于所有 'a)的情况。

我已经尝试了一段时间来弄清楚这个 for <'a> 的语法,但没能成功。

生命周期不能是函数本身的模板参数,因为引用只存在于其中。

考虑到 GAT 是一个不稳定的功能,这是否可能?

playground

#![feature(generic_associated_types)]

// Trait definitions.

trait Builder {
    type InstanceForBuilder<'a>: Instance<'a>;

    fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a>;
}

trait Instance<'a> {
    // Some functions will only work when the instance has some concrete associated type.
    type InstanceProperty;
}

fn build_with_42_for_bool<B: Builder>(builder: B)
where
    // TODO: What do I put here to make this work?
    for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
{
    builder.build(&42);
    // Do some testing here. The Instance won't be returned.
}

// Now try it out.

struct MyBuilder;
struct MyInstance<'a> {
    val: &'a usize,
}

impl Builder for MyBuilder {
    type InstanceForBuilder<'a> = MyInstance<'a>;

    fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a> {
        MyInstance { val }
    }
}

impl<'a> Instance<'a> for MyInstance<'a> {
    type InstanceProperty = bool;
}

fn main() {
    let builder = MyBuilder;
    build_with_42_for_bool(builder); // TODO: Doesn't work
}

在我的实际代码中,build_with_42_for_bool 是一个测试助手,它以特定方式构造传递给 build 的参数。现在我可能只是在所有地方内联那个函数,因为唯一的问题是如何指定这个函数的生命周期。代码本身工作正常。

这是完整的错误:

Compiling pairwise-aligner v0.1.0 (/home/philae/git/eth/git/astar-pairwise-aligner)
error[E0271]: type mismatch resolving `for<'a> <<_ as Builder>::InstanceForBuilder<'a> as Instance<'a>>::InstanceProperty == bool`
  --> examples/test.rs:45:5
   |
45 |     build_with_42(builder); // TODO: Doesn't work
   |     ^^^^^^^^^^^^^ expected `bool`, found associated type
   |
   = note:         expected type `bool`
           found associated type `<<_ as Builder>::InstanceForBuilder<'_> as Instance<'_>>::InstanceProperty`
   = help: consider constraining the associated type `<<_ as Builder>::InstanceForBuilder<'_> as Instance<'_>>::InstanceProperty` to `bool`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `build_with_42`
  --> examples/test.rs:19:53
   |
16 | fn build_with_42<B: Builder>(builder: B)
   |    ------------- required by a bound in this
...
19 |     for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `build_with_42`

error[E0271]: type mismatch resolving `for<'a> <MyBuilder as Builder>::InstanceForBuilder<'a> == <MyBuilder as Builder>::InstanceForBuilder<'a>`
  --> examples/test.rs:45:5
   |
45 |     build_with_42(builder); // TODO: Doesn't work
   |     ^^^^^^^^^^^^^ type mismatch resolving `for<'a> <MyBuilder as Builder>::InstanceForBuilder<'a> == <MyBuilder as Builder>::InstanceForBuilder<'a>`
   |
note: expected this to be `<MyBuilder as Builder>::InstanceForBuilder<'a>`
  --> examples/test.rs:32:35
   |
32 |     type InstanceForBuilder<'a> = MyInstance<'a>;
   |                                   ^^^^^^^^^^^^^^
   = note: expected associated type `<MyBuilder as Builder>::InstanceForBuilder<'a>`
                       found struct `MyInstance<'a>`
help: a method is available that returns `<MyBuilder as Builder>::InstanceForBuilder<'a>`
  --> examples/test.rs:8:5
   |
8  |     fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Builder::build`
note: required by a bound in `build_with_42`
  --> examples/test.rs:19:40
   |
16 | fn build_with_42<B: Builder>(builder: B)
   |    ------------- required by a bound in this
...
19 |     for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `build_with_42`

For more information about this error, try `rustc --explain E0271`.
error: could not compile `pairwise-aligner` due to 2 previous errors

执行所需操作的正确语法是:

where B::InstanceForBuilder::InstanceProperty = bool

没有必要引入for<'a>生命周期,因为关联类型的值不允许依赖于生命周期参数。如果你compile this code,你会发现你得到另一个错误:

error: equality constraints are not yet supported in `where` clauses
  --> src/main.rs:19:5
   |
19 |     B::InstanceForBuilder::InstanceProperty = bool,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
   |
   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information

没有立即解决此问题的方法。如果你非常需要这个,你可以写一个新的特性,只为 bool 实现它,然后将事情限制在那个特性上。不过很快就会变得混乱。