Нужно ли реализовывать черту дважды при ее реализации как для ссылочных, так и для нереферентных типов? - PullRequest
1 голос
/ 12 июня 2019

Я хочу реализовать признак как для ссылочного, так и для не ссылочного типа. Нужно ли реализовывать функции дважды, или это не идиоматично для этого?

Вот демонстрационный код:

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

Ответы [ 3 ]

4 голосов
/ 12 июня 2019

Это хороший пример для черты Borrow.

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();
}
2 голосов
/ 15 июня 2019

Вы можете использовать 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 заключается в том, что вы знаете, были ли данные переданы по значению или по ссылке, если это имеет значение длявы.

2 голосов
/ 12 июня 2019

Нет, вам не нужно дублировать код.Вместо этого вы можете делегировать:

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

Я бы пошел еще дальше и реализовал черту для всех ссылок на типы, которые реализуют эту черту:

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

См. Также:


&bar.hi();

Этот код эквивалентен &(bar.hi()) и, вероятно, не соответствует вашим ожиданиям.

См. Также:

...