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
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.