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

时间:2016-06-29 17:41:24

标签: rust

为什么代码示例1编译但示例2给出了编译错误?

示例1:

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) }
    }
}

示例2:

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
 import java.util.{Collections, WeakHashMap}
 case class Memoized[T,R](f: T => R) extends Function1[T,R] {
    val mem = Collections.synchronizedMap(new WeakHashMap[T,R])
    def apply(t: T) = Option(mem.get(t)).getOrElse { 
      val r = f(t)
      mem.put(t, r)
      r
    }
 }

1 个答案:

答案 0 :(得分:3)

归结为“这是一个很好的理由”,但好的理由并不是那么复杂。

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

// 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();
}

该程序应该输出什么?对于library::Speaklibrary::Dog有两个同等有效,无法区分的实现;没有正确的答案。更糟糕的是,如果我最初依赖woof并稍后添加bark,我的代码将停止编译,或者 - 更糟糕 - 开始透明地做错事。冲突的特质冲动是一件坏事。

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

// 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都有一个,只有一个,它可以被放置。这样,我们就不用担心冲突了;如果正确设置了孤儿规则,它们应该是不可能的。

规则归结为:当你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 E0117rustc --explain E0210