生锈 – 为什么一致性规则会引发错误“类型参数必须用作某些本地类型的类型参数”?

为什么代码示例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) }
    }
}

例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) }
    }
}
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
它确实归结为“有一个很好的理由”,但好的理由并不是那么复杂.

这是问题所在.想象一下,我有一个图书馆箱子:

// library.rs
pub struct Dog;
pub trait Speak {
    fn speak(&self);
}

还有两个使用该库箱的板条箱.

// bark.rs
extern crate library;
impl library::Speak for library::Dog {
    fn speak(&self) {
        println!("woof");
    }
}
// woof.rs
extern crate library;
impl library::Speak for library::Dog {
    fn speak(&self) {
        println!("bark");
    }
}

现在,出于某种原因,我想使用这两个库:

// main.rs
extern crate library;
extern crate woof;
extern crate bark;

fn main() {
   let rex = library::Dog;
   rex.speak();
}

该程序应该输出什么?有两个同样有效,难以区分的库实现:: Speak for library :: Dog;没有正确的答案.更糟糕的是,如果我最初依赖于woof,并且稍后添加了树皮,我的代码将停止编译,或者 – 更糟糕 – 开始透明地做错误的事情.冲突的特质冲动是一件坏事™.

添加泛型时会变得更糟.如果你有:

// barkgeneric.rs
extern crate library;
impl<T> library::Speak for T {
    fn speak(&self) {
        println!("woof");
    }
}
// woofgeneric.rs
extern crate library;
impl<T> library::Speak for T {
    fn speak(&self) {
        println!("bark");
    }
}

你现在有无数的冲突特质冲动.哎呦.

为了避免这个问题,我们有了孤儿规则.孤儿规则的想法是确保任何impl Trait for Type都有一个,只有一个,它可以被放置.这样,我们不必担心冲突;如果孤立规则设置正确,它们应该是直接的.

规则归结为:当你为一个类型提供特征时,特征或类型必须来自当前的条件箱.这使我所有相互矛盾的例子都行不通. woof.rs无法实现library :: speak for library :: Dog,因为它们都不是来自它的箱子.

同样,你不能impl< T>索引<有界>为[T; 4] ;,因为[T; 4]并非来自你的箱子,而且rustc已经决定了Index< Bounded>也不算是来自你的箱子.

但是,它确实让你的impl指数< Bounded>为[i32; 4]到,因为在这种情况下Index< Bounded>确实来自你.这可能是一个错误,但它也可能只是预期的行为;孤儿规则比我在这里所说的稍微复杂一些,并且它们可能以奇怪的方式进行交互.

有关更多细节,请参见rustc --explain E0117,rustc --explain E0210.

相关文章
相关标签/搜索