在为引用和非引用类型实现特性时,我是否必须实现特性两次?
Do I have to implement a trait twice when implementing it for both reference and non-reference types?
我想为引用类型和非引用类型实现一个特征。我是否必须实现这些功能两次,或者这不是惯用的做法?
这是演示代码:
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();
}
这是 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();
}
不,您不必复制代码。相反,您可以委派:
impl Foo for &'_ Bar {
fn hi(&self) {
(**self).hi()
}
}
我会更进一步,为所有对实现该特征的类型的引用实现该特征:
impl<T: Foo> Foo for &'_ T {
fn hi(&self) {
(**self).hi()
}
}
另请参阅:
- Implementing a trait for reference and non reference types causes conflicting implementations
&bar.hi();
此代码等同于 &(bar.hi())
,可能不是您想要的。
另请参阅:
您可以使用 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
相比的一个优势是您知道数据是按值传递还是按引用传递(如果这对您很重要)。
我想为引用类型和非引用类型实现一个特征。我是否必须实现这些功能两次,或者这不是惯用的做法?
这是演示代码:
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();
}
这是 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();
}
不,您不必复制代码。相反,您可以委派:
impl Foo for &'_ Bar {
fn hi(&self) {
(**self).hi()
}
}
我会更进一步,为所有对实现该特征的类型的引用实现该特征:
impl<T: Foo> Foo for &'_ T {
fn hi(&self) {
(**self).hi()
}
}
另请参阅:
- Implementing a trait for reference and non reference types causes conflicting implementations
&bar.hi();
此代码等同于 &(bar.hi())
,可能不是您想要的。
另请参阅:
您可以使用 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
相比的一个优势是您知道数据是按值传递还是按引用传递(如果这对您很重要)。