考虑以下两个特征:
pub trait Foo {
fn new(arg: u32) -> Self;
}
pub trait Bar<P>: Foo {
fn with_parameter(arg: u32, parameter: P) -> Self;
}
我想添加毯子impl:
impl<T: Bar<P>, P: Default> Foo for T {
fn new(arg: u32) -> Self {
Self::with_parameter(arg, P::default())
}
}
但是我收到了编译错误:
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
我认为我收到此错误是因为我违反了特质一致性规则,但我并不完全明白这会违反什么规则。为什么不允许这种模式?而且,更重要的是,我可以实现我想要的而不会出错吗?
答案 0 :(得分:7)
问题是单个类型可以为Bar<P>
的多个值实现P
。如果您有一个实现Baz
和Bar<i32>
的结构Bar<String>
,Foo::new
应使用哪种类型?{/ p>
唯一的解决方案是确保单个类型不能多次实现P
(如果这不是您想要的,那么您的设计就有缺陷!)。为此,我们必须将Bar
类型参数替换为关联类型。
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())
}
}
的实现如下所示:
Bar
另见:
答案 1 :(得分:1)
我已经细分并扩展了Francis's explanation为什么代码无法编译的原因。我可能不是最聪明的孩子,但是我花了很长时间才了解他的简洁推理。
让我们创建Baz
,它以两个变体实现Bar
:i32
和String
:
struct Baz;
impl Bar<i32> for Baz { /* ... */ }
impl Bar<String> for Baz { /* ... */ }
一揽子隐含生效后的类型依赖图:
-> trait Bar<i32> -> trait Foo (with i32 baked-in)
struct Baz
-> trait Bar<String> -> trait Foo (with String baked-in)
我们最终得到Foo
的2种不同实现:内置i32
和内置String
。
当我们编写<Baz as Foo>::new()
时,编译器无法分辨出我们指的是Foo
的哪个版本。他们是无法区分的。
经验法则是,仅当特征A在特征B的所有通用参数上通用时,特征A才能对特征B具有全面的实现。