关联类型的等式约束的替代

问题描述

我正在尝试用 Rust 编写此代码:

trait Foo {
    type T: PartialEq;

    fn get_t(&self) -> Self::T;
}

struct Bar<F1: Foo,F2: Foo> {
    f1: F1,f2: F2,}

impl<F1: Foo,F2: Foo> Bar<F1,F2> {
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

它拒绝编译,因为 F1::T 可能与 F2::T 不同,从而使等式变得毫无意义。我希望能够通过写这个来解决这个问题:

impl<F1: Foo,F2>
where
    F1::T = F2::T
{
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

但这告诉我尚不支持等式约束,并让我参考 this issue。由于它自 2014 年底开始开放,我怀疑它不会很快推出。

我可以做到这一点,它会编译:

struct Bar<T: PartialEq,F1: Foo<T=T>,F2: Foo<T=T>> {
    f1: F1,}

impl<T: PartialEq,F2: Foo<T=T>> Bar<T,F1,F2>
{
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

但随后我向结构体 Bar 添加了一个额外的通用参数。如果 Foo 有多个我想以这种方式约束的关联类型,那么它会变得有点混乱。 我的问题是:

  1. 通过添加附加类型参数 Bar 使 T 变得“更通用”,这真的是我强制执行此约束的唯一方法吗?
  2. 这是解决这个问题最惯用的方法吗?

编辑:

我意识到我过于简化了我的例子。 假设我实际上有一个 Bar,它有一个关联的 Baz,它有一个关联的 Foo,它有一个关联的 T。 有点啰嗦,下面是例子:

trait Foo {
    type T: PartialEq;

    fn get_t(&self) -> Self::T;
}

trait Baz {
    type F: Foo;

    fn get_inner_t(&self) -> <Self::F as Foo>::T;
}

struct Bar<B1: Baz,B2: Baz> {
    b1: B1,b2: B2,}

impl<B1: Baz,B2: Baz> Bar<B1,B2>
{
    
    fn test_eq(&self) -> bool {
        self.b1.get_inner_t() == self.b2.get_inner_t()
    }
}

当然它仍然无法编译,因为 T 中的 get_inner_t 可能不同。我确实希望允许两个 Baz 不同,Foo 不同,但将它们的 T 限制为相同。

我试图通过写作来调整给出的答案

impl<B1: Baz,B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1,B2>

但这会导致编译错误:

   Compiling type_bindings v0.1.0 (/home/harry/coding/rust_sandbox/type_bindings)
error: expected one of `(`,`,`::`,`<`,or `>`,found `=`
  --> src/main.rs:18:38
   |
18 | impl<B1: Baz,B2>
   |                                      ^ expected one of `(`,or `>`

error: aborting due to previous error

error: could not compile `type_bindings`

To learn more,run the command again with --verbose.

如果这种关联类型的多级提取不被允许?

解决方法

您可以“提取”关联类型:

struct Bar<F1: Foo,F2: Foo<T = <F1 as Foo>::T>> {
    f1: F1,f2: F2,}

impl<F1: Foo,F2: Foo<T = <F1 as Foo>::T>> Bar<F1,F2>
{
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

对于您的编辑,您可以使用一些类型别名来清理语法(不是必需的但更好),然后使用 impl 或向 impl 添加另一个泛型(这不会使结构更通用,因此它不会遇到相同的问题,但是它不允许您将边界放在结构上):

type GetT<T> = <T as Foo>::T;
type GetF<T> = <T as Baz>::F;

impl<B1: Baz,B2: Baz<F = impl Foo<T = GetT<GetF<B1>>>>> Bar<B1,B2>
{
    
    fn test_eq(&self) -> bool {
        self.b1.get_inner_t() == self.b2.get_inner_t()
    }
}

impl<T: PartialEq,B1: Baz<F = impl Foo<T = T>>,B2: Baz<F = impl Foo<T = T>>> Bar<B1,B2>
{
    
    fn test_eq(&self) -> bool {
        self.b1.get_inner_t() == self.b2.get_inner_t()
    }
}
,

虽然@Aplet123 指出的所有内容都是有效的,但我认为这是一种在语法上更简洁的编写方式。

trait Foo {
    type T: PartialEq;

    fn get_t(&self) -> Self::T;
}

struct Bar<F1,F2>
where
    F1: Foo,F2: Foo<T = F1::T>,{
    f1: F1,}

impl<F1,F2> Bar<F1,{
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}
trait Foo {
    type T: PartialEq;

    fn get_t(&self) -> Self::T;
}

trait Baz {
    type F: Foo;

    fn get_inner_t(&self) -> <Self::F as Foo>::T;
}

struct Bar<B1,B2>
where
    B1: Baz,B2: Baz<F = B1::F>,{
    b1: B1,b2: B2,}

impl<B1,B2> Bar<B1,{
    fn test_eq(&self) -> bool {
        self.b1.get_inner_t() == self.b2.get_inner_t()
    }
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...