首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么在关联的类型上不能识别除第一个外的上性状界限?

为什么在关联的类型上不能识别除第一个外的上性状界限?
EN

Stack Overflow用户
提问于 2018-06-03 04:29:35
回答 1查看 388关注 0票数 5

此代码段在Rust 1.26.1中有效:

代码语言:javascript
复制
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都应该有效。如on the playground所示,t += &t2是有效的,但using t += t2 isn't

代码语言:javascript
复制
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实现的,这显然是错误的,因为它实现了需要AddAssign<Self>Trait

如果我们更改TraitAddAssign界限的顺序,则相反的情况成立:t += t2 is valid while t += &t2 isn't

这个问题的一个快速解决方案是将func generic over both traits

代码语言:javascript
复制
fn func<T: Trait, T2: Trait2<Associated = T>>() {
    let mut t = T2::method(1);
    let t2 = T2::method(2);
    t += t2;
}

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

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

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

这是怎么回事?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-03 07:30:40

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

  1. Higher-ranked trait bounds on associated types are not elaborated (#50346).
  2. where clauses are only elaborated for supertraits, and not other things (#20671)
  3. Constraints on associated types declared in subtraits do not propagate. (#32722)
  4. Unrecognized associated type bound on another associated type (#24159)

解决方法是重申每个使用地点的界限:

代码语言:javascript
复制
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,这都应该得到解决,对于复杂的类型系统所产生的问题,它是一个更有原则的解决方案。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50660911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档