简体   繁体   English

为什么我不能在带有类型参数的特征上添加一个全面的实现?

[英]Why can't I add a blanket impl on a trait with a type parameter?

Consider these two traits:考虑这两个特征:

pub trait Foo {
    fn new(arg: u32) -> Self;
}

pub trait Bar<P>: Foo {
    fn with_parameter(arg: u32, parameter: P) -> Self;
}

I'd like to add the blanket impl:我想添加一揽子实现:

impl<T: Bar<P>, P: Default> Foo for T {
    fn new(arg: u32) -> Self {
        Self::with_parameter(arg, P::default())
    }
}

But I get the compiler error:但我收到编译器错误:

error[E0207]: the type parameter `P` is not constrained by the impl trait, self type, or predicates
 --> src/lib.rs:9:17
  |
9 | impl<T: Bar<P>, P: Default> Foo for T {
  |                 ^ unconstrained type parameter

I think I get this error because I'm violating trait coherence rules, but I don't understand exactly what rule this would break.我想我收到这个错误是因为我违反了特征一致性规则,但我不明白这会破坏什么规则。 Why is this pattern not allowed?为什么不允许这种模式? And, more importantly, can I achieve what I want without getting an error?而且,更重要的是,我可以在不出错的情况下实现我想要的吗?

The problem is that a single type could implement Bar<P> for multiple values of P .的问题是,单一类型的可以实现Bar<P>为的多个值P If you had a struct Baz that implemented Bar<i32> and Bar<String> , which type should Foo::new use for P ?如果你有一个结构体Baz实现了Bar<i32>Bar<String> ,那么Foo::new应该为P使用哪种类型?

The only solution is to ensure that a single type cannot implement Bar more than once (if that's not what you want, then you have a flaw in your design!).唯一的解决方案是确保单个类型不能多次实现Bar (如果这不是您想要的,那么您的设计就有缺陷!)。 To do so, we must replace the P type parameter with an associated type.为此,我们必须用关联类型替换P类型参数。

pub trait Bar: Foo {
    type Parameter;

    fn with_parameter(arg: u32, parameter: Self::Parameter) -> Self;
}

impl<T> Foo for T
where
    T: Bar,
    T::Parameter: Default,
{
    fn new(arg: u32) -> Self {
        Self::with_parameter(arg, T::Parameter::default())
    }
}

An implementation of Bar would look like this: Bar的实现如下所示:

struct Baz;

impl Bar for Baz {
    type Parameter = i32;

    fn with_parameter(arg: u32, parameter: Self::Parameter) -> Self {
        unimplemented!()
    }
}

See also:也可以看看:

I've broken down and extended Francis's explanation of why the code does not compile.我已经分解并扩展了Francis对代码无法编译的原因的解释 I may not be the smartest kid on the block, but it took me way too long to understand his concise reasoning.我可能不是街区里最聪明的孩子,但我花了太长时间才理解他简洁的推理。

Let's create Baz , which implements Bar in 2 variants: i32 and String :让我们创建Baz ,它在 2 个变体中实现Bari32String

struct Baz;

impl Bar<i32> for Baz { /* ... */ }

impl Bar<String> for Baz { /* ... */ }

Type dependency graph after blanket impl takes effect:覆盖 impl 生效后的类型依赖图:

           -> trait Bar<i32>    -> trait Foo (with i32 baked-in)
struct Baz
           -> trait Bar<String> -> trait Foo (with String baked-in)

We end up with 2 different implementations of Foo : with baked-in i32 and with baked-in String .我们最终得到了Foo两种不同实现:内置i32和内置String When we write <Baz as Foo>::new() , compiler can't tell which version of Foo we mean;当我们将<Baz as Foo>::new() ,编译器无法分辨我们指的是哪个版本的Foo they are indistinguishable.它们是无法区分的。

The rule of a thumb is that trait A can have blanket implementation for trait B only if trait A is generic over all generic parameters of trait B.经验法则是,只有当 trait A 对 trait B 的所有泛型参数是通用的时,trait A 才能对 trait B 进行全面实现。

暂无
暂无

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

相关问题 为什么我不能将类型参数添加到覆盖方法? - Why can't I add a type parameter to an overriding method? 如果已经将特征边界添加到另一个impl块,为什么还要在其上添加特征边界? - Why do I need to add trait bounds on impl blocks if I've already added them to another impl block? 为什么我不能在扩展通用特征的类中调用带有参数“ this”的方法? - Why can't I call a method with parameter `this` in a class extending a generic trait? 如何在另一个泛型类型的特征绑定的类型参数上表达特征? - How can I express a trait bound on a type parameter for another generic type's trait bound? 如何在结构本身不需要泛型参数的通用 impl 块中添加类型注释? - How to add type annotations to generic impl block where the struct itself doesn't require a generic parameter? 为什么我不能在 Kotlin 中使用 Class 类型作为泛型参数? - Why I can't use a Class type as a generic parameter in Kotlin? 为什么我不能在Java中创建类型参数的数组? - Why can't I create an array of a type parameter in Java? 在Scala中,为什么不能在此处显式使用参数类型? - In Scala, why can't I explicitly use a parameter type here? 为什么我不能用 let _: Arc 创建一个特征 object<dyn trait> = value.into()?</dyn> - Why can't I create a trait object with let _: Arc<dyn Trait> = value.into()? 为什么我不能将&#39;as&#39;用于限制为接口的泛型类型参数? - Why can't I use 'as' with generic type parameter that is constrained to be an interface?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM