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

后端 未结 3 749
心在旅途
心在旅途 2020-12-02 02:16

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 t

相关标签:
3条回答
  • 2020-12-02 02:43

    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();
    }
    
    0 讨论(0)
  • 2020-12-02 02:54

    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?
    0 讨论(0)
  • 2020-12-02 02:56

    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.

    0 讨论(0)
提交回复
热议问题