我有一个名为Sleep
的特性:
pub trait Sleep {
fn sleep(&self);
}
我可以为每个结构提供sleep
的不同实现,但事实证明大多数人以很少的方式睡觉。你可以睡在床上:
pub trait HasBed {
fn sleep_in_bed(&self);
fn jump_on_bed(&self);
}
impl Sleep for HasBed {
fn sleep(&self) {self.sleep_in_bed()}
}
如果你在野营,你可以睡在帐篷里:
pub trait HasTent {
fn sleep_in_tent(&self);
fn hide_in_tent(&self);
}
impl Sleep for HasTent {
fn sleep(&self) {self.sleep_in_tent()}
}
有一些古怪的案例。我有一个可以靠墙站着睡觉的朋友,但大多数时候,大多数人都陷入了一些简单的情况。
我们定义一些结构并让它们sleep
:
struct Jim;
impl HasBed for Jim {
fn sleep_in_bed(&self) { }
fn jump_on_bed(&self) { }
}
struct Jane;
impl HasTent for Jane {
fn sleep_in_tent(&self) { }
fn hide_in_tent(&self) { }
}
fn main() {
use Sleep;
let jim = Jim;
jim.sleep();
let jane = Jane;
jane.sleep();
}
嗯,哦!编译错误:
error: no method named `sleep` found for type `Jim` in the current scope
--> src/main.rs:43:9
|
43 | jim.sleep();
| ^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `sleep`, perhaps you need to implement it:
= help: candidate #1: `Sleep`
error: no method named `sleep` found for type `Jane` in the current scope
--> src/main.rs:46:10
|
46 | jane.sleep();
| ^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `sleep`, perhaps you need to implement it:
= help: candidate #1: `Sleep`
这个编译器错误很奇怪,因为如果实现另一个特性的特性出现问题,我希望在我这样做的时候听到它回来,当我尝试使用结果时,不是在程序的最底层。
在这个例子中,只有2种结构和2种睡眠方式,但在一般情况下,有许多结构和几种睡眠方式(但没有结构的多种方式)。
Bed
主要是Sleep
的实现,但在一般情况下,Bed
有很多用途,可以实现很多功能。
唯一明显的方法是将impl Sleep for...
转换为结构自身使用的宏,但这看起来很糟糕而且非常糟糕。
答案 0 :(得分:16)
您需要为实现第一个特征的对象实现第二个特征:
impl<T> Sleep for T
where
T: HasBed
{
fn sleep(&self) {self.sleep_in_bed()}
}
但是,只要添加第二个,这就会破裂:
impl<T> Sleep for T
where
T:HasTent
{
fn sleep(&self) {self.sleep_in_tent()}
}
使用
error[E0119]: conflicting implementations of trait `Sleep`:
--> src/main.rs:52:1
|
42 | / impl<T> Sleep for T
43 | | where
44 | | T: HasBed,
45 | | {
... |
48 | | }
49 | | }
| |_- first implementation here
...
52 | / impl<T> Sleep for T
53 | | where
54 | | T: HasTent,
55 | | {
... |
58 | | }
59 | | }
| |_^ conflicting implementation
有可能实施 HasBed
和HasTent
。如果出现了同时实现的内容,那么代码现在就不明确了。
你如何实现目标?我想你已经提出了目前最好的解决方案 - 写一个宏。在您can write your own deriving之前,这可能被视为权宜之计。宏确实不是那么糟糕,但写起来却很笨拙。
另一件事,可能完全基于您为您的示例选择的名称,将简单地将结构嵌入到其他结构中,可选地将它们公之于众。由于您Sleep
的实施基本上只取决于床/帐篷,因此这样做不会丢失功能。当然,有些人可能会觉得打破了封装。您可以再次创建宏来实现各种委派。
trait Sleep { fn sleep(&self); }
struct Bed;
impl Bed { fn jump(&self) {} }
impl Sleep for Bed { fn sleep(&self) {} }
struct Tent;
impl Tent { fn hide(&self) {} }
impl Sleep for Tent { fn sleep(&self) {} }
struct Jim { bed: Bed }
struct Jane { tent: Tent }
fn main() {
let jim = Jim { bed: Bed };
jim.bed.sleep();
}
答案 1 :(得分:15)
我们可以在这里使用相关项目。
pub trait Sleep: Sized {
type Env: SleepEnv;
fn sleep(&self, env: &Self::Env) {
env.do_sleep(self);
}
fn get_name(&self) -> &'static str;
}
pub trait SleepEnv {
fn do_sleep<T: Sleep>(&self, &T);
}
然后,我们实现两种不同的睡眠环境。
struct Bed;
struct Tent;
impl SleepEnv for Bed {
fn do_sleep<T: Sleep>(&self, person: &T) {
println!("{} is sleeping in bed", person.get_name());
}
}
impl SleepEnv for Tent {
fn do_sleep<T: Sleep>(&self, person: &T) {
println!("{} is sleeping in tent", person.get_name());
}
}
最后一部分是它们的具体实现。
struct Jim;
struct Jane;
impl Sleep for Jim {
type Env = Bed;
fn get_name(&self) -> &'static str {
"Jim"
}
}
impl Sleep for Jane {
type Env = Tent;
fn get_name(&self) -> &'static str {
"Jane"
}
}
测试代码:
fn main() {
let bed = Bed;
let tent = Tent;
let jim = Jim;
let jane = Jane;
jim.sleep(&bed);
jane.sleep(&tent);
}