【问题标题】:Do I have to implement a trait twice when implementing it for both reference and non-reference types?在为引用类型和非引用类型实现特征时,我是否必须两次实现特征?
【发布时间】:2019-06-12 06:31:51
【问题描述】:

我想为引用类型和非引用类型实现一个特征。我是否必须两次实现这些功能,或者这样做不习惯?

这是演示代码:

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

【问题讨论】:

标签: rust traits


【解决方案1】:

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

【讨论】:

  • 这不适用于Into/TryInto/From/TryFrom。有解决办法吗?
【解决方案2】:

不,您不必复制代码。相反,您可以委托:

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

我会更进一步,为实现该特征的类型的所有引用实现该特征:

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

另见:


&bar.hi();

此代码等同于&amp;(bar.hi()),可能不是您想要的。

另见:

【讨论】:

    【解决方案3】:

    你可以使用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");
    }
    

    Borrow 相比的一个优势是,您知道数据是按值传递还是按引用传递,如果这对您很重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-08
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多