Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
993 views
in Technique[技术] by (71.8m points)

rust - Why do the coherence rules raise the error "the type parameter must be used as the type parameter for some local type"?

Why does code example 1 compile but example 2 gives a compilation error?

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

Example 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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It does boil down to "there's a good reason", but the good reason isn't all that complicated.

Here's the problem. Imagine I've got a library crate:

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

And two crates that use that library crate.

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

Now, for some reason, I want to use both of these libraries:

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

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

What should this program output? There are two equally valid, indistinguishable implementations of library::Speak for library::Dog; there isn't a right answer. What's worse, if I depended on woof originally, and added bark later, my code would stop compiling, or - worse - start transparently doing the wrong thing. Conflicting trait impls are a Bad Thing?.

It gets worse when you add generics. If you have:

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

You now have an infinite number of conflicting trait impls. Whoops.

To avoid this problem, we have the orphan rules. The idea of the orphan rules is to make sure that any impl Trait for Type has one, and only one, place it can be put. That way, we don't have to worry about impl conflicts; they should be straight-up impossible, if the orphan rules are set up correctly.

The rules boil down to: when you impl a trait for a type, either the trait or the type has to come from the current crate. This makes all of my conflicting examples not work. woof.rs can't implement library::speak for library::Dog, because it neither of them come from its crate.

Similarly, you can't impl<T> Index<Bounded> for [T; 4];, because [T; 4] doesn't come from your crate, and rustc has decided that Index<Bounded> doesn't count as coming from your crate either.

It does, however, let your impl Index<Bounded> for [i32; 4] through, because in this case Index<Bounded> does come from you. It's possible that's a bug, but it's also possible that it's just intended behavior; the orphan rules are slightly more complex than what I've stated here, and they might be interacting in weird ways.

For more specifics, see rustc --explain E0117, rustc --explain E0210.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...