简体   繁体   中英

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

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

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

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:


&bar.hi();

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

See also:

You can use Cow :

use std::borrow::Cow;

#[derive(Clone)]
struct Bar;

trait Foo {
    fn hi(self) -> &'static str;
}

impl<'a, B> Foo for B where B: Into<Cow<'a, Bar>> {
    fn hi(self) -> &'static str {
        let bar = self.into();

        // bar is either owned or borrowed:
        match bar {
            Cow::Owned(_) => "Owned",
            Cow::Borrowed(_) => "Borrowed",
        }
    }
}

/* Into<Cow> implementation */

impl<'a> From<Bar> for Cow<'a, Bar> {
    fn from(f: Bar) -> Cow<'a, Bar> {
        Cow::Owned(f)
    }
}

impl<'a> From<&'a Bar> for Cow<'a, Bar> {
    fn from(f: &'a Bar) -> Cow<'a, Bar> {
        Cow::Borrowed(f)
    }
}

/* Proof it works: */

fn main() {
    let bar = &Bar;
    assert_eq!(bar.hi(), "Borrowed");

    let bar = Bar;
    assert_eq!(bar.hi(), "Owned");
}

The one advantage over Borrow is that you know if the data was passed by value or reference, if that matters to you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM