impl Trait 的原语和引用

impl Trait for primitives and references of

也许这是一个简单的问题,但我不明白为什么只是为原始的、拥有的类型实现 Trait,我免费获得了相同的引用类型实现...

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

这不仅仅是因为原语,它适用于实现 Copy 的所有类型。否则将不起作用:

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();
}

失败并显示明确的错误代码:

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

发生的事情是,使用 Copy 类型时,rust 会在需要时透明地为您创建一个副本。

请注意,即使我们注释掉前一行 // nc.cool();,它也会失败,这显然移动了值...

那是auto-dereferencing;只要您使用 . 运算符,它就适用。它旨在消除 C 和相关语言中存在的 .-> 之间的区别。

它是在 RFC 241 中引入的。