为什么我不能在带有类型参数的特征上添加毯子impl?

Oth*_*ers 7 generics traits type-parameter rust

考虑以下两个特征:

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

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

我想添加毯子impl:

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

但是我得到了编译器错误:

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
Run Code Online (Sandbox Code Playgroud)

我想我得到了这个错误,因为我违反了特质一致性规则,但我不明白究竟会破坏什么规则.为什么不允许这种模式?而且,更重要的是,我可以实现我想要的而不会出错吗?

Fra*_*gné 9

问题是单个类型可以实现Bar<P>多个值P.如果你有一个结构Baz是实现Bar<i32>Bar<String>,哪种类型应该Foo::new使用P

唯一的解决方案是确保单个类型不能实现Bar多次(如果这不是您想要的,那么您的设计就有缺陷!).为此,我们必须用P相关类型替换type参数.

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())
    }
}
Run Code Online (Sandbox Code Playgroud)

一个实现Bar将如下所示:

struct Baz;

impl Bar for Baz {
    type Parameter = i32;

    fn with_parameter(arg: u32, parameter: Self::Parameter) -> Self {
        unimplemented!()
    }
}
Run Code Online (Sandbox Code Playgroud)


Cod*_*ich 6

我已经分解并扩展了弗朗西斯对代码无法编译的原因的解释。我可能不是这个街区最聪明的孩子,但我花了太长时间才理解他简洁的推理。

让我们创建Baz,它Bar以 2 种变体实现:i32String

struct Baz;

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

impl Bar<String> for Baz { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

Blank impl 生效后的类型依赖图:

struct Baz;

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

impl Bar<String> for Baz { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

我们最终得到了 2 种不同的实现Foo: with Baked-ini32和 with Baked-in String。当我们编写 时<Baz as Foo>::new(),编译器无法判断Foo我们指的是哪个版本;它们是无法区分的。

经验法则是,只有当特征 A 对于特征 B 的所有通用参数是通用的时,特征 A 才能对特征 B 进行全面实现。