一般特征实施的'继承'

Byr*_*ron 1 rust

我想尝试一般地实现特征,并且只要它们是兼容的,特征的用户就会自动继承这个"基础"实现.

这是测试代码我想出了(注意,fmt::Showstd::fmt::Show):

trait Outspoken {
    fn speak(&self) -> String;
}

impl<T: fmt::Show> Outspoken for T {
    fn speak(&self) -> String {
        format!("{:?}", self)
    }
}

// In theory, we can now let my-types speak
#[derive(Show)]
struct MyType(i32);

// 'Show' works
assert_eq!(format!("{:?}", MyType(15)), "MyType(15)");
// speak() however, doesn't
let mti = MyType(20);
mti.speak();
Run Code Online (Sandbox Code Playgroud)

但是,生锈并不知道这MyType是通用实现的可行候选者,因为它还没有将特性与它联系起来.上面的代码产生以下错误:

tests/lang.rs:523:9: 523:16 error: type `generics_and_traits::MyType` does not implement any method in scope named `speak` tests/lang.rs:523 mti.speak(); ^~~~~~~ tests/lang.rs:523:16: 523:16 help: methods from traits can only be called if the trait is implemented and in scope; the following trait defines a method `speak`, perhaps you need to implement it: tests/lang.rs:523:16: 523:16 help: candidate #1: `generics_and_traits::Outspoken` error: aborting due to previous error

如何将特征与我的类型相关联? 有没有其他方法可以实现这一目标而不是实际实现这一特性?

我的结论

批准的答案显然是实现这一目标的绝对正确方法.为了完整起见,我正在展示我同时提出的代码,这也告诉我如何修改特征.

获得的经验是,通用系统中的特征像标记一样用于选择(并因此限制)要应用通用实现的类型集.

如果要将接口与使用此类接口的通用实现分开,特性修正很有用,这些接口应自动提供给实现特征的任何人.

然后,可以使用在批准的答案中看到的通用特征实现来自动使特征对于与通用边界匹配的类型可用.

trait Outspoken : fmt::Debug {};

trait Outspoken : fmt::Debug {};

// This defines a default implementation to any Trait. : Outspoken is any bound
trait OutspokenImpl : Outspoken {
    fn speak(&self) -> String {
        format!("{:?}", self)
    }
}

// This line tells the generics system to provide the implementation to all types
// which are outspoken
impl<T> OutspokenImpl for T where T: Outspoken {}

#[derive(Debug)]
struct MyType(i32);

// Add Outspoken marker to my type
impl Outspoken for MyType {};


assert_eq!(format!("{:?}", MyType(15)), "MyType(15)");
let mti = MyType(20);
assert_eq!(mti.speak(), "MyType(20)");

// You can bark even though the implementation follows later.
// Makes sense as we handle generics at compile time
assert_eq!(mti.bark(), "wuff");

// Add your own methods to any existing type who is Outspoken
trait AmendDoggyness : Outspoken {
    fn bark(&self) -> &str {
        "wuff"
    }
}

impl<T> AmendDoggyness for T where T: Outspoken {}any bound
trait OutspokenImpl : Outspoken {
    fn speak(&self) -> String {
        format!("{:?}", self)
    }
}

// This line tells the generics system to provide the implementation to all types
// which are outspoken
impl<T> OutspokenImpl for T where T: Outspoken {}

#[derive(Debug)]
struct MyType(i32);

// Add Outspoken marker to my type
impl Outspoken for MyType {};


assert_eq!(format!("{:?}", MyType(15)), "MyType(15)");
let mti = MyType(20);
assert_eq!(mti.speak(), "MyType(20)");

// You can bark even though the implementation follows later.
// Makes sense as we handle generics at compile time
assert_eq!(mti.bark(), "wuff");

// Add your own methods to any existing type who is Outspoken
trait AmendDoggyness : Outspoken {
    fn bark(&self) -> &str {
        "wuff"
    }
}

impl<T> AmendDoggyness for T where T: Outspoken {}
Run Code Online (Sandbox Code Playgroud)

DK.*_*DK. 6

问题是,截至最后一天左右(由于RFC 565),它不再被调用Show.您需要使用Debug:

#![allow(unstable)]
use std::borrow::ToOwned;
use std::fmt::Debug;

trait Outspoken {
    fn speak(&self) -> String;
}

impl<T> Outspoken for T where T: Debug {
    fn speak(&self) -> String {
        format!("{:?}", self)
    }
}

#[derive(Debug)]
struct MyType(i32);

fn main() {
    assert_eq!(format!("{:?}", MyType(15)), "MyType(15)");
    assert_eq!(MyType(20).speak(), "MyType(20)".to_owned());
}
Run Code Online (Sandbox Code Playgroud)