Reputation: 8764
I have a function that can handle both owned and borrowed values of some type Foo
by accepting a Cow<'_, Foo>
. However, I'd like to make it more convenient by allowing to pass in owned or borrowed Foo
s directly.
Is it possible to have a conversion trait to Cow
that's implemented both on a reference type and its owned version?
This is what I tried:
trait Convert<'a> : Clone {
fn into_cow(self) -> Cow<'a, Self>;
}
// Works
impl<'a> Convert<'a> for Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("owned");
Cow::Owned(self)
}
}
// Doesn't work
impl<'a> Convert<'a> for &'a Foo {
fn into_cow(self) -> Cow<'a, Self> {
println!("borrowed");
Cow::Borrowed(self)
}
}
The borrowed version says that Borrowed
expected a &&'a Foo
but found a &'a Foo
.
Upvotes: 2
Views: 310
Reputation: 6109
Do you ever make use of the ownership, or always reborrow it? If only reborrowing, is std::convert::AsRef
what you're looking for?
fn take_foo(foo: impl AsRef<Foo>) {
let foo: &Foo = foo.as_ref();
todo!();
}
Upvotes: 0
Reputation: 8764
Self
in the implementation of a trait for &Foo
is &Foo
, so into_cow()
doesn't return the same type in both impls.
One solution would be to change the return type to Cow<'a, Foo>
, but that of course limits the trait to only work on Foo
.
A better way is to make the owned type a generic parameter of Convert
like this:
trait Convert<'a, T: Clone> {
fn into_cow(self) -> Cow<'a, T>;
}
impl<'a, T: Clone> Convert<'a, T> for T {
fn into_cow(self) -> Cow<'a, T> {
println!("owned");
Cow::Owned(self)
}
}
impl<'a, T: Clone> Convert<'a, T> for &'a T {
fn into_cow(self) -> Cow<'a, T> {
println!("borrowed");
Cow::Borrowed(self)
}
}
fn take_foo<'a>(foo: impl Convert<'a, Foo>) {
let cow = foo.into_cow();
}
fn main() {
take_foo(&Foo{});
take_foo(Foo{});
}
Upvotes: 1