简体   繁体   English

要求在继承特征的关联类型上绑定特征

[英]Requiring a trait bound on the associated type of an inherited trait

I have a trait Foo inheriting from another trait Bar .我有一个特征Foo继承自另一个特征Bar Bar has an associated type Baz . Bar有一个关联类型Baz Foo constrains Baz such that Baz must implement Hoge . Foo约束Baz使得Baz必须实现Hoge

trait Hoge {}

trait Bar {
    type Baz;
}

trait Foo: Bar where Self::Baz: Hoge {}

However, when I define a generic function requiring the generic type T to implement Foo ,但是,当我定义一个泛型 function 需要泛型类型T来实现Foo时,

// [DESIRED CODE]
fn fizz<T: Foo>(buzz: T) {
    // ...
}

rustc complains with EO277 unless I constrain T explicitly: rustc抱怨EO277除非我明确限制T

fn fizz<T: Foo>(buzz: T) where T::Baz: Hoge {
    // ...
}

I do not understand why I need to do this.我不明白为什么我需要这样做。 I would like to be able to write [DESIRED CODE] .我希望能够编写[DESIRED CODE] What is the recommended way to do this?推荐的方法是什么?

Sadly (or not), you have to repeat the bounds. 可悲的是(或者不是),您必须重复边界。

Last year I opened a issue thinking that the type checker was being inconsistent. 去年,我提出了一个问题 ,认为类型检查器不一致。 The code is similar to yours. 该代码与您的代码相似。

@arielb1 closed the issue and said that this was the intended behavior and gave this explanation: @ arielb1解决了该问题,并说这是预期的行为,并给出了以下解释:

The thing is that we don't want too many bounds to be implicitly available for functions, as this can lead to fragility with distant changes causing functions to stop compiling. 事实是,我们不希望太多的边界隐式地用于函数,因为这会导致脆弱性以及遥远的更改,从而导致函数停止编译。 There are basically 3 kinds of bounds available to a function: 函数基本上有3种范围可用:

  • bounds from explicit where-clauses - eg T: B when you have that clause. 明确的where子句的边界-例如,当您拥有该子句时为T: B This includes the "semi-explicit" Sized bound. 这包括“半显式” Sized限制。
  • bounds from supertraits of explicit where-clauses - a where-clause adds bounds for its supertraits (as trait B: A , the T: B bound adds a T: A bound). 显式where子句的超性的边界-where子句为其上等性添加边界(作为trait B: AT: B边界添加T: A边界)。
  • bounds from the lifetime properties of arguments (outlives/implicator/implied bounds). 参数生存期属性的边界(生存期/隐含子/隐含边界)。 These are only lifetime bounds, and irrelevant for the current problem. 这些仅是生命周期的界限,与当前问题无关。 rust-lang/rfcs#1214 involved them a great deal. rust-lang / rfcs#1214涉及了很多。

If your bound isn't in the list, you will have to add it explicitly if you want to use it. 如果绑定不在列表中,则要使用它必须显式添加。 I guess this should be a FAQ entry. 我想这应该是常见问题解答条目。

Today I opened an issue to request that this information to be added to the docs. 今天,我打开了一个问题 ,要求将此信息添加到文档中。

It is possible to work around this behaviour by using another associated type in Foo since the compiler accepts implicit bounds when part of the associated type definition ( playground ):可以通过在Foo中使用另一个关联类型来解决此行为,因为当关联类型定义 ( playground ) 的一部分时,编译器接受隐式边界:

trait Foo: Bar<Baz = Self::HogeBaz> {
    type HogeBaz: Hoge;
}

The new associated type can be hidden in a helper trait to avoid having to include it in every implementation.新的关联类型可以隐藏在辅助特性中,以避免必须在每个实现中都包含它。 Full example (with renaming for clarity) ( playground )完整示例(为清楚起见重命名)( 游乐场

trait Bound {
    fn bound();
}

trait Trait {
    type Type;
}

trait BoundedTypeHelper: Trait<Type = Self::BoundedType> {
    type BoundedType: Bound;
}

impl<T> BoundedTypeHelper for T
where
    T: Trait,
    Self::Type: Bound,
{
    type BoundedType = Self::Type;
}

trait UserTrait: BoundedTypeHelper {}

fn fizz<T: UserTrait>() {
    T::Type::bound()
}

I am with you in thinking that the original where-based bound ought to be treated as part of the trait definition and applied implicitly.我同意你的看法,认为原始的基于 where 的界限应该被视为特征定义的一部分并隐式应用。 It feels very arbitrary that bounding associated types inline works but where clauses do not.绑定关联类型内联有效但where子句无效感觉非常随意。

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

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