Generics 为什么可以';我不能在带有类型参数的特征上添加一个毯子impl吗?

Generics 为什么可以';我不能在带有类型参数的特征上添加一个毯子impl吗?,generics,rust,traits,type-parameter,Generics,Rust,Traits,Type Parameter,考虑以下两个特点: pub trait Foo { fn new(arg: u32) -> Self; } pub trait Bar<P>: Foo { fn with_parameter(arg: u32, parameter: P) -> Self; } pub-trait-Foo{ fn新(arg:u32)->Self; } 酒吧特色酒吧:Foo{ 带_参数的fn(arg:u32,参数:P)->Self; } 我想加一条毯子: impl<

考虑以下两个特点:

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

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

:Foo{ 带_参数的fn(arg:u32,参数:P)->Self; }

我想加一条毯子:

impl<T: Bar<P>, P: Default> Foo for T {
    fn new(arg: u32) -> Self {
        Self::with_parameter(arg, P::default())
    }
}
impl Foo for T{
fn新(参数:u32)->自{
Self::with_参数(arg,P::default())
}
}
但我得到了编译器错误:

error[E0207]:类型参数'P'不受impl-trait、self-type或谓词的约束
-->src/lib.rs:9:17
|
9 |对T的建议{
|^无约束类型参数

我想我之所以会犯这个错误是因为我违反了特质一致性规则,但我不知道这会打破什么规则。为什么不允许这种模式?更重要的是,我能在不出错的情况下实现我想要的吗?

问题是单一类型可以为
pBar
ode>。如果您有一个实现了
Bar
Bar
的结构
Baz
,那么
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())
    }
}
另见:


问题在于,单个类型可以为
p
的多个值实现
Bar
。如果您有一个实现了
Bar
Bar
的结构
Baz
,那么
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())
    }
}
另见:


我已经详细分析并扩展了代码无法编译的原因。我可能不是最聪明的孩子,但我花了太长时间才理解他的简明推理

让我们创建
Baz
,它以两种变体实现
Bar
i32
String

struct Baz;

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

impl Bar<String> for Baz { /* ... */ }
structbaz;
Baz{/*…*/}的impl条
Baz{/*…*/}的impl条
一揽子实施生效后的类型依赖关系图:

->trait Bar->trait Foo(带i32烘焙)
结构Baz
->特征条->特征Foo(带烘焙字符串)
我们最终得到了两种不同的
Foo
实现:使用baked-in
i32
和baked-in
String
。 当我们编写
::new()
时,编译器无法分辨我们指的是哪个版本的
Foo
;它们是无法区分的


经验法则是,只有当trait a在trait B的所有泛型参数上都是泛型的,trait a才能对trait B进行全面实现。

我已经详细分析并扩展了代码不编译的原因。我可能不是这一块上最聪明的孩子,但我花了太长时间才理解他的简明推理

让我们创建
Baz
,它以两种变体实现
Bar
i32
String

struct Baz;

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

impl Bar<String> for Baz { /* ... */ }
structbaz;
Baz{/*…*/}的impl条
Baz{/*…*/}的impl条
一揽子实施生效后的类型依赖关系图:

->trait Bar->trait Foo(带i32烘焙)
结构Baz
->特征条->特征Foo(带烘焙字符串)
我们最终得到了两种不同的
Foo
实现:使用baked-in
i32
和baked-in
String
。 当我们编写
::new()
时,编译器无法分辨我们指的是哪个版本的
Foo
;它们是无法区分的

经验法则是,只有在特性a在特性B的所有通用参数上都是通用的情况下,特性a才能对特性B有全面的实现