'继承'通用特质实施

时间:2015-01-25 10:26:11

标签: rust

我想尝试一般性地实施一个特征,让特质的用户继承这个特征' base'只要它们兼容,就会自动执行。

这是我提出的测试代码(注意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();

但是,生锈并不知道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

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

我的结论

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

经验教训是,通用系统中的 traits 被用作标记来选择(并因此限制)要应用通用实现的类型集。

如果您希望将界面与使用此类界面的通用实现分开,那么特征修正很有用,这些界面应自动提供给实现特征的任何人。

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

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 {}

1 个答案:

答案 0 :(得分: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());
}