为什么代码示例1编译但示例2给出了编译错误?
例1:
use std::ops::Index;
struct Bounded {
idx: usize,
}
impl Index<Bounded> for [i32; 4] {
type Output = i32;
fn index(&self, b: Bounded) -> &i32 {
unsafe { self.get_unchecked(b.idx) }
}
}
Run Code Online (Sandbox Code Playgroud)
例2:
use std::ops::Index;
struct Bounded {
idx: usize,
}
impl<T> Index<Bounded> for [T; 4] {
type Output = T;
fn index(&self, b: Bounded) -> &T {
unsafe { self.get_unchecked(b.idx) }
}
}
Run Code Online (Sandbox Code Playgroud)
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
--> src/main.rs:7:1
|
7 | impl<T> Index<Bounded> for [T; 4] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter
Run Code Online (Sandbox Code Playgroud)
它确实可以归结为“有一个充分的理由”,但充分的理由并不那么复杂。
\n\n问题就在这里。想象一下我有一个图书馆箱子:
\n\n// library.rs\npub struct Dog;\npub trait Speak {\n fn speak(&self);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n还有两个使用该库板条箱的板条箱。
\n\n// bark.rs\nextern crate library;\nimpl library::Speak for library::Dog {\n fn speak(&self) {\n println!("woof");\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n// woof.rs\nextern crate library;\nimpl library::Speak for library::Dog {\n fn speak(&self) {\n println!("bark");\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n现在,出于某种原因,我想使用这两个库:
\n\n// main.rs\nextern crate library;\nextern crate woof;\nextern crate bark;\n\nfn main() {\n let rex = library::Dog;\n rex.speak();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这个程序应该输出什么?library::Speakfor有两个同样有效、无法区分的实现library::Dog;没有正确的答案。更糟糕的是,如果我woof原来依赖,并添加bark后来添加,我的代码将停止编译,或者 - 更糟糕 - 开始透明地做错误的事情。冲突的特征实现是一件坏事\xe2\x84\xa2。
当你添加泛型时,情况会变得更糟。如果你有:
\n\n// barkgeneric.rs\nextern crate library;\nimpl<T> library::Speak for T {\n fn speak(&self) {\n println!("woof");\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n// woofgeneric.rs\nextern crate library;\nimpl<T> library::Speak for T {\n fn speak(&self) {\n println!("bark");\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n你现在拥有无限个相互冲突的特质实现。哎呀。
\n\n为了避免这个问题,我们有孤儿规则。孤儿规则的想法是确保任何impl Trait for Type都有一个且只有一个可以放置的位置。这样,我们就不必担心 impl 冲突;如果孤儿规则设置正确的话,它们应该是完全不可能的。
这些规则归结为:当您impl为某个类型添加特征时,该特征或该类型必须来自当前的板条箱。这使得我所有相互矛盾的例子都不起作用。woof.rs无法library::speak实现library::Dog,因为它们都不是来自它的板条箱。
同样,您也不能impl<T> Index<Bounded> for [T; 4];,因为它[T; 4]不是来自您的板条箱,并且rustc已决定Index<Bounded>也不算是来自您的板条箱。
然而,它确实让你impl Index<Bounded> for [i32; 4]通过,因为在这种情况下Index<Bounded>确实来自你。这可能是一个错误,但也可能只是预期的行为;孤儿规则比我在这里所说的稍微复杂一些,并且它们可能以奇怪的方式相互作用。
有关更多详细信息,请参阅rustc --explain E0117、rustc --explain E0210。
| 归档时间: |
|
| 查看次数: |
381 次 |
| 最近记录: |