繁体   English   中英

为什么在关联类型上无法识别除第一个之外的超特征边界?

[英]Why are supertrait bounds other than the first not recognized on an associated type?

此代码段在 Rust 1.26.1 中有效:

use std::ops::AddAssign;

trait Trait
where
    for<'a> Self: AddAssign<Self> + AddAssign<&'a Self> + Sized,
{
}

trait Trait2 {
    type Associated: Trait;

    fn method(u32) -> Self::Associated;
}

fn func<T2: Trait2>() {
    let mut t = T2::method(1);
    let t2 = T2::method(2);
    t += &t2;
}

请注意, Trait实现了AddAssign<Self>AddAssign<&'a Trait> (按这个顺序,这在后面很重要)。 因此,在func我们知道t += t2t += &t2都应该是有效的。 正如在操场上看到t += &t2是有效的,但使用t += t2不是

error[E0308]: mismatched types
  --> src/main.rs:19:10
   |
19 |     t += t2;
   |          ^^
   |          |
   |          expected reference, found associated type
   |          help: consider borrowing here: `&t2`
   |
   = note: expected type `&<T2 as Trait2>::Associated`
              found type `<T2 as Trait2>::Associated`

我读到这个错误是因为编译器没有认识到AddAssign<Self>是为T::Associated ,这显然是错误的,因为它实现了Trait ,它需要AddAssign<Self>

如果我们更改TraitAddAssign边界的顺序,则相反: t += t2有效t += &t2无效

该问题的快速解决方法是使func 对两个特征都通用

fn func<T: Trait, T2: Trait2<Associated = T>>() {
    let mut t = T2::method(1);
    let t2 = T2::method(2);
    t += t2;
}

这不应该是必要的; 编译器可以识别AddAssign之一,为什么不能识别另一个? 似乎最后一个界限是要被识别的界限。

我的第一个怀疑是这与动态调度有关。 我排除了它,因为即使在动态调度中边界的顺序也不重要。 我什至不认为它使用它,因为所有类型在编译时使用单态化都是已知的。

我目前的怀疑是一个编译器错误,当它是关联类型时,类型检查器不考虑特征边界上的泛型。 很容易想象这样一个特定的案例被忽视了。

这是怎么回事?

这是一个已知的错误(或几个的组合):

  1. 没有详细说明相关类型的更高级别特征边界 (#50346)
  2. where 子句仅针对超特征进行阐述,而不针对其他内容(#20671)
  3. 子特征中声明的关联类型的约束不会传播。 (#32722)
  4. 无法识别的关联类型绑定到另一个关联类型 (#24159)

解决方法是在每个使用站点重新声明边界:

fn func<T2>()
where
    T: Trait2,
    T::Associated: Trait,
{
    let mut t = T::method(1);
    let t2 = T::method(2);
    t += &t2;
    t += t2;
}

当类型系统从其临时实现转移到Chalk 时,应该解决这个问题, Chalk是一个更原则性的解决方案,用于解决复杂类型系统创建的问题类型。

暂无
暂无

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

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