0

Perhaps it is a simple question, but I can't understand why just impl'ing Trait for the primitive, owned type, I got for free the same impl for reference types...

trait Cool: Sized + std::fmt::Debug {
    fn cool(self) {
        println!("cool -> {:?}", self);
    }
}

impl Cool for i32 {}

// it still works if this line is uncommented...
// impl Cool for &i32 {}

fn main(){
    let val = 123;
    val.cool();
    (&val).cool();
}

Playground

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
rsalmei
  • 3,085
  • 1
  • 14
  • 15
  • Essentially method lookup for `&&&i32` will look for implementations for `&&&i32`, `&&i32`, `&i32`, and `i32` (which the last only works because `i32` is `Copy`). – kmdreko Jun 01 '22 at 18:44
  • 1
    Note that `&i32` **does not** implement `Cool` unless you explicitly do so; you can call it _as if it would_ because of autoref, but you can't pass it for example to a function that expects `impl Cool`. – Chayim Friedman Jun 01 '22 at 18:51

2 Answers2

1

It is not just because of primitives, it will work for all types that implement Copy. Will not work otherwise:

trait Cool: Sized + std::fmt::Debug {
    fn cool(self) {
        println!("cool -> {:?}", self);
    }
}

#[derive(Debug)]
struct NonCopy;

impl Cool for i32 {}
impl Cool for NonCopy {}

fn main(){
    let val = 123;
    val.cool();
    (&val).cool();
    
    let nc = NonCopy{};
    nc.cool();
    (&nc).cool();
}

Fails with a clear error code:

error[E0507]: cannot move out of a shared reference
  --> src/main.rs:20:5
   |
20 |     (&nc).cool();
   |     ^^^^^^------
   |     |     |
   |     |     value moved due to this method call
   |     move occurs because value has type `NonCopy`, which does not implement the `Copy` trait
   |

Playground

What it's happening is that with the Copy types rust creates a copy transparently for you when needed.

Note that it fails even if we comment out the previous line // nc.cool();, which obviously moves the value...

rsalmei
  • 3,085
  • 1
  • 14
  • 15
Netwave
  • 40,134
  • 6
  • 50
  • 93
1

That's auto-dereferencing; it applies whenever you use the . operator. It's meant to erase the distinction between . and -> which exists in C and related languages.

It was introduced in RFC 241.

coriolinus
  • 879
  • 2
  • 8
  • 18