Search code examples
rusttraitsownershipborrowing

Unable to call a function with a reference to a type implementing a trait


I am having some trouble to understand how to work with Traits and ownerships. The following example works:

struct X([u8; 4]);

impl X {
   pub fn get(&self, n: usize) -> u8 {
       self.0[n]
   }
}

fn f1(x: &X) {
    println!("{}", x.get(1));
    f2(&x);
}

fn f2(x: &X) {
    println!("{}", x.get(2));    
}

fn main() {
    let z1 = X([1u8, 2u8, 3u8, 4u8]);
    f1(&z1);
}

But when I try to create a trait (here XT) with get:

trait XT {
  fn get(&self, n: usize) -> u8;
}

struct X([u8; 4]);

impl XT for X {
   fn get(&self, n: usize) -> u8 {
       self.0[n]
   }
}

fn f1<T: XT>(x: &T) {
    println!("{}", x.get(1));
    f2(&x);
}

fn f2<T: XT>(x: &T) {
    println!("{}", x.get(2));    
}

fn main() {
    let z1 = X([1u8, 2u8, 3u8, 4u8]);
    f1(&z1);
}

Fails to compile with the following error message:

the trait XT is not implemented for the type &T

It works if I change f2(&x) to f2(x). My expectation was that replacing the types by the traits, everything will work.


Solution

  • The problem is that you're trying to pass &&T to f2. That means it expects &T to implement XT, and that's not what you said: you said that T implements XT.

    You can modify f1 to properly express this constraint by using a where T: XT, for<'a> &'a T: XT clause, but then you can't call f1 from main because &X doesn't implement XT. So you go and add an implementation for that as well, and then the code works... but honestly, it's easier to just remove that & and call f2(x) instead.

    To put it another way: just because a type implements a trait does not mean pointers to that type also implement the trait.