初识 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 声明块内不能包含完全相同的 成员方法-签名”? 但下面的代码是合法的。 要是我理解错了,你最好能给一个非法的例子。