我想尝试通用地实现一个特征,并让该特征的用户在兼容的情况下自动继承这个“基础”实现。
这是我想出的测试代码(注意 fmt::Show
是 std::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();
但是,rust 不知道 MyType
是通用实现的可行候选者,因为它还没有将特征与其相关联。上面的代码会产生以下错误:
tests/lang.rs:523:9: 523:16 错误:类型 `generics_and_traits::MyType` 没有在名为 `speak` 的范围内实现任何方法
测试/lang.rs:523 mti.speak();
^~~~~~~
tests/lang.rs:523:16: 523:16 帮助:只有当特征被实现并且在范围内时,才能调用来自特征的方法;下面的 trait 定义了一个方法 `speak`,也许你需要实现它:
测试/lang.rs:523:16:523:16 帮助:候选人#1:`generics_and_traits::Outspoken`
错误:由于先前的错误而中止
如何将特征与我的类型相关联? 是否有任何替代方案来实现这一目标而不是实际实现该特征?
我的结论
批准的答案显然是实现这一点的绝对正确方法。为了完整起见,我展示了我同时想出的代码,这也教会了我如何修改特征。
经验教训是,traits 在通用系统中用作标记来选择(并因此限制)您要应用通用实现的类型集。
如果你想将你的接口(interface)与使用此类接口(interface)的通用实现分开,特性修正很有用,它应该自动提供给任何实现你特性的人。
然后可以使用已批准答案中的通用特征实现来自动使特征可用于匹配通用边界的类型。
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 {}
最佳答案
问题是,截至大约最后一天(由于 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());
}
关于rust - 通用特征实现的“继承”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28135373/