孤儿规则和一致性是 Rust trait 系统里最「反直觉」的两条限制。这篇不背规则,而是把各种组合都编译一遍,让编译器自己说明:什么能写、什么不能写、为什么连「看起来没冲突」的实现也会被拒绝。
外部 trait + 外部类型(Display for Vec<u8>)
→ 失败:error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate
本地 trait + 外部类型(MyTr for Vec<u8>)
→ 编译通过
外部 trait + 本地类型(Display for Local)
→ 编译通过
外部 trait + 外部类型,但 trait 的类型参数是本地类型(From<Local> for Vec<u8>)
→ 编译通过
外部 trait + Box<本地类型>(Box 是 #[fundamental])
→ 编译通过
外部 trait + Vec<本地类型>(Vec 不是 fundamental)
→ 失败:error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the cratenewtype 的做法见Newtype 模式。
源码:
1 | trait Describe { fn d(&self) -> String; }
2 | impl<T: std::fmt::Display> Describe for T { fn d(&self) -> String { format!("显示:{}", self) } }
3 | impl Describe for i32 { fn d(&self) -> String { "整数".into() } }
4 | fn main() {}
编译:失败
error[E0119]: conflicting implementations of trait `Describe` for type `i32`
--> <实验目录>/src/u47a.rs:3:1
|
2 | impl<T: std::fmt::Display> Describe for T { fn d(&self) -> String { format!("显示:{}", self) } }
| ----------------------------------------- first implementation here
3 | impl Describe for i32 { fn d(&self) -> String { "整数".into() } }
| ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`. 源码:
1 | trait Describe { fn d(&self) -> String; }
2 | impl<T: std::fmt::Display> Describe for T { fn d(&self) -> String { format!("显示:{}", self) } }
3 | impl Describe for Vec<u8> { fn d(&self) -> String { "字节向量".into() } }
4 | fn main() {}
编译:失败
error[E0119]: conflicting implementations of trait `Describe` for type `Vec<u8>`
--> <实验目录>/src/u47b.rs:3:1
|
2 | impl<T: std::fmt::Display> Describe for T { fn d(&self) -> String { format!("显示:{}", self) } }
| ----------------------------------------- first implementation here
3 | impl Describe for Vec<u8> { fn d(&self) -> String { "字节向量".into() } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Vec<u8>`
|
= note: upstream crates may add a new impl of trait `std::fmt::Display` for type `std::vec::Vec<u8>` in future versions
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.
源码:
1 | trait Describe { fn d(&self) -> String; }
2 | impl<T: std::fmt::Display> Describe for T { fn d(&self) -> String { format!("显示:{}", self) } }
3 | struct Mine; // 本地类型:上游永远不会给它实现 Display
4 | impl Describe for Mine { fn d(&self) -> String { "我的类型".into() } }
5 | fn main() { println!("{} {}", Mine.d(), 5.d()); }
编译:成功
运行(退出码 0):
我的类型 显示:5blanket 实现的更多例子见Blanket Implementation。
源码:
1 | use std::fmt;
2 | struct Bytes(Vec<u8>); // newtype
3 | impl fmt::Display for Bytes { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} 字节", self.0.len()) } }
4 | trait Hex { fn hex(&self) -> String; } // 自己的 trait,可以为外部类型实现
5 | impl Hex for Vec<u8> { fn hex(&self) -> String { self.iter().map(|b| format!("{b:02x}")).collect() } }
6 | fn main() { println!("{} / {}", Bytes(vec![1, 2, 3]), vec![0xde, 0xad].hex()); }
编译:成功
运行(退出码 0):
3 字节 / dead