初识 impl Trait for Type {...}
,我自以为 Trait
与实现类 Type
是“自由选择”的(戏称之:脚本思维后遗症)。其实,在给定 crate
内,什么 Type
能实现什么 Trait
还是有几条基本的“戒律”要守的。总结来就两条:
- 孤儿原则
Trait
不重叠原则
若不能同时满足这两条原则,rustc
会认定【Trait
实现不一致】而抛出编译错误。咱们从最容易理解的原则讲起。
【Trait
不重叠原则】
补充说明:这条限制,从RFC 1210(大约 2020 年)之后,就已经被去掉了。
若同一个 Type
同时实现多个 Trait
(,当然就会同时存在多个 Trait
实现块),那么这多个 Trait
声明块内不能包含完全相同的:
- 成员方法-签名
- 关联函数-签名
- 关联常量
- 关联类型别名
这个好理解,咱们不能让同一个签名有多套不一样实现,不是?这会让 rustc
无所适从的。
【孤儿原则】
依据【Trait
实现块】采用的语法不同,对【孤儿原则】的解释也小有差异:
- 形式一:
impl Trait for T0 {...}
Trait
与T0
之一必须是在当前crate
内被定义。它们不能同时都是来自于第三方crate
。- 其实,【形式一 】是【形式二】的一款简化特例。
- 形式二:
impl<P1..Pm> Trait<T1.., Ti, .., Tn> for T0 {...}
- 要么,
Trait
是在当前crate
内被定义。 - 要么,同时满足下面两个条件
Ti
是T0..=Tn
列表里第一个在当前crate
内定义的具体类型。- 而
T0
自身是否来自于第三方crate
并不重要,只要它是·具体类型·,就行。
- 而
P1..=Pm
最多只能出现在(Ti, Tn]
的左开右闭区间(Rust
没有这类区间的表达符号)内,而不能落在T0..Ti
左闭右开区间内。
- 要么,
【孤儿原则的例外】
impl Trait for Box<Type> {...}
虽然 Box 定义是在标准库里,但只要 Type
是在当前 crate
内被定义,此·Trait
实现·即被认为是·一致的·。即,Box<Type>
就能实现 Trait
。
【后记】
P1..=Pm
是【实现块】的【类型参数】。术语:Uncovered
类型参数。T1..=Tn
是被实现Trait
自己的【类型参数】。..=
是Rust
对【闭区间】的表示语法。- 在
for
关键字之前是应该有where
从句以标注【类型参数】的【限定条件】的。但,这里为了简单将其省略了。
1
共 2 条评论, 1 页
评论区
写评论感谢学友的热心回复,我上 Google 仔细查阅了一下从RFC 1210 开始,rustc 放宽了对【Trait Implementation Coherence】的限制和去掉了【overlapping implementation instances】限制,从而让 Rust 更符合人类工程学。大约在 2020 年这个 RFC 完全落地。
嗯。我的知识与经验有点落后了。
--
👇
viruscamp: 下面代码的 impl X for T1 的 fn f(&mut self) impl Y for T1 的 fn f(&mut self) 算不算是 “多个 Trait 声明块内不能包含完全相同的 成员方法-签名”? 但下面的代码是合法的。 要是我理解错了,你最好能给一个非法的例子。
下面代码的 impl X for T1 的 fn f(&mut self) impl Y for T1 的 fn f(&mut self) 算不算是 “多个 Trait 声明块内不能包含完全相同的 成员方法-签名”? 但下面的代码是合法的。 要是我理解错了,你最好能给一个非法的例子。