Possible bug, or just misunderstanding?


#1

I have an example where I do not understand the error message rust is giving me. The following looks like valid code to me (it’s a simplified version of a real example):

pub trait TestTrait {
    fn foo(&self) -> u8;
}

impl TestTrait for [u8] {
    fn foo(&self) -> u8 {
        self[0]
    }
}

pub fn nice<T: TestTrait>(x: &T) -> u8 {
    x.foo()
}

#[cfg(test)]
mod tests {
    use super::{TestTrait, nice};

    #[test]
    fn it_works() {
        let x: [u8; 32] = [0; 32];
        let y: &[u8] = &x[0..4];
        println!("y.foo() is {:?}", y.foo());
        println!("nice(y) is {:?}", nice(y));
    }
}

However, it fails with a message that:

…error: the trait core::marker::Sized is not implemented for the type [u8] [E0277]
src/lib.rs:24 println!(“nice(y) is {:?}”, nice(y));

I don’t understand why Sized would be needed, as at no attempt am I trying to pass or copy a [u8]. The argument y is a &[u8], which is sized. What’s going on here?

David


#2

IIUC, Sized is implicit in every generic type, and you have to opt out using ?Sized, i.e. with

pub fn nice<T: TestTrait + ?Sized>(x: &T) -> u8

it will work, see http://is.gd/zczF78


#3

While the type of y is &[u8] which is also Sized, the nice function matches the argument against &T, so T happens to be [u8], which is unsized. You can relax the constraints by using the suggestion from @birkenfeld, or you could implement TestTrait for &[u8], not for [u8], which is to say:

impl<'a> TestTrait for &'a [u8] {
    fn foo(&self) -> u8 {
        self[0]
    }
}

pub fn nice<T: TestTrait>(x: T) -> u8 {
    x.foo()
}

A working version here.


#4

Thanks, guys, those two answers were exactly what I needed. I had had
difficulty implementing the trait for the reference, because I hadn’t
figured out that I needed to declare the lifetime as impl<'a>.

David