Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I have to implement a trait twice when implementing it for both reference and non-reference types?

Tags:

rust

traits

I want to implement a trait for both a for reference and non-reference type. Do I have to implement the functions twice, or this is not idiomatic to do so?

Here's the demo code:

struct Bar {}

trait Foo {
    fn hi(&self);
}

impl<'a> Foo for &'a Bar {
    fn hi(&self) {
        print!("hi")
    }
}

impl Foo for Bar {
    fn hi(&self) {
        print!("hi")
    }
}

fn main() {
    let bar = Bar {};
    (&bar).hi();
    &bar.hi();
}
like image 592
davyzhang Avatar asked Jun 12 '19 06:06

davyzhang


2 Answers

This is a good example for the Borrow trait.

use std::borrow::Borrow;

struct Bar;

trait Foo {
    fn hi(&self);
}

impl<B: Borrow<Bar>> Foo for B {
    fn hi(&self) {
        print!("hi")
    }
}

fn main() {
    let bar = Bar;
    (&bar).hi();
    &bar.hi();
}
like image 158
hellow Avatar answered Sep 24 '22 15:09

hellow


No, you do not have to duplicate code. Instead, you can delegate:

impl Foo for &'_ Bar {
    fn hi(&self) {
        (**self).hi()
    }
}

I would go one step further and implement the trait for all references to types that implement the trait:

impl<T: Foo> Foo for &'_ T {
    fn hi(&self) {
        (**self).hi()
    }
}

See also:

  • When should I not implement a trait for references to implementors of that trait?
  • Implementing a trait for reference and non reference types causes conflicting implementations

&bar.hi();

This code is equivalent to &(bar.hi()) and probably not what you intended.

See also:

  • Why is it legal to borrow a temporary?
like image 39
Shepmaster Avatar answered Sep 20 '22 15:09

Shepmaster