Newbie: Trait implementaion collision issue


#1

Hi, I am straggling to understand why compiler has an issue with my code. Seems to me that for some reason it complains because it thinks that my implementations collide and I don’t understand why.
I would appreciate if somebody would explain this to me. Thank you.
I am running rust 1.7 (rustc 1.7.0 (a5d1e7a59 2016-02-29))

Here is example 1:

trait Test<T> {
    fn value(&self, v: T);
}

struct Test1;
impl<'a> Test<&'a[u8]> for Test1 {
    fn value(&self, v: &'a[u8]) {
        println!("value: {:?}", v);
    }
}

fn main() {
    let t = Test1;
    t.value(&[1, 2]);
    t.value(&[1, 2, 3]);
}

Output:
Compiling rust_test v0.1.0 (file://…/rust_test)
Running target/debug/rust_test
value: [1, 2]
value: [1, 2, 3]

Great!

Here is example 2:

trait Test<T> {
    fn value(&self, v: T);
}
struct Test1;
impl Test<u8> for Test1 {
    fn value(&self, v: u8) {
        println!("value: {:?}", v);
    }
}
impl<'a> Test<&'a[u8]> for Test1 {
    fn value(&self, v: &'a[u8]) {
        println!("value: {:?}", v);
    }
}

fn main() {
    let t = Test1;
    t.value(32);
    t.value(&[1, 2]);
    t.value(&[1, 2, 3]);
}

Output:
Compiling rust_test v0.1.0 (file://…/rust_test)
src/main.rs:22:7: 22:21 error: the trait Test<&[_; 2]> is not implemented for the type Test1 [E0277]
src/main.rs:22 t.value(&[1, 2]);
^~~~~~~~~~~~~~
src/main.rs:22:7: 22:21 help: run rustc --explain E0277 to see a detailed explanation
src/main.rs:22:7: 22:21 help: the following implementations were found:
src/main.rs:22:7: 22:21 help: <Test1 as Test>
src/main.rs:22:7: 22:21 help: <Test1 as Test<&'a [u8]>>
src/main.rs:23:7: 23:24 error: the trait Test<&[_; 3]> is not implemented for the type Test1 [E0277]
src/main.rs:23 t.value(&[1, 2, 3]);
^~~~~~~~~~~~~~~~~
src/main.rs:23:7: 23:24 help: run rustc --explain E0277 to see a detailed explanation
src/main.rs:23:7: 23:24 help: the following implementations were found:
src/main.rs:23:7: 23:24 help: <Test1 as Test>
src/main.rs:23:7: 23:24 help: <Test1 as Test<&'a [u8]>>
error: aborting due to 2 previous errors
Could not compile rust_test.indent preformatted text by 4 spaces


#2

The compiler has trouble choosing the correct implementation of Test when there are more than one alternative. To understand a bit more why, you will have to understand the relationship between &[T] and arrays. &[T] is not a reference to an array, but a reference to a slice of (or a piece of) contiguous memory. That memory can, in turn, be an array or a vector, to name a couple. The actual type name for an array is [T; N], where N is the length of the array. You can see them in the above error messages as [_; 2] and [_; 3].

So, how come you can use arrays instead of slices? Well, the compiler can assume that you want to use a slice if you give it a reference to an array where it expects a slice. That’s so you don’t have to explicitly slice it every time. This is what makes your first example work. The compiler sees that the only implementation where the value method exists expects it to take a slice as the argument, so it borrows your arrays as slices.

The second example offers two implementations where the value method exists, so the compiler decides to give you an error instead of guessing (and potentially causing a more serious problem). You can help it on its way using a few different methods:

//Tell it that the elements are of type u8 and that it
//should be cast as a slice of something,
t.value(&[1u8, 2] as &[_]);

//or slice the array using the index syntax,
t.value(&[1, 2][..]);

//or use a variable with an explicit type
let a1: &[u8] = &[1, 2];
t.value(a1);

They are all ok, and which one to choose depends on what you are doing and how you like it. There may be even more ways, but these are the ones I could think of right now.


#3

Thank you very much. It makes perfect sense now. I completely missed the fact that &[T] syntax refers to slice and not array.