Rust 我为另一个trait实现了一个trait,但无法从这两个trait调用方法
我有一种叫做睡眠的特质:Rust 我为另一个trait实现了一个trait,但无法从这两个trait调用方法,rust,traits,Rust,Traits,我有一种叫做睡眠的特质: pub trait Sleep { fn sleep(&self); } 我可以为每个结构提供不同的睡眠实现,但事实证明,大多数人的睡眠方式很少。你可以睡在床上: pub trait HasBed { fn sleep_in_bed(&self); fn jump_on_bed(&self); } impl Sleep for HasBed { fn sleep(&self) { sel
pub trait Sleep {
fn sleep(&self);
}
我可以为每个结构提供不同的睡眠实现,但事实证明,大多数人的睡眠方式很少。你可以睡在床上:
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()
}
}
有一些奇怪的情况。我有一个朋友可以靠墙睡觉,但大多数人,大多数时候,都会陷入一些简单的情况
我们定义一些结构并让它们休眠:
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[E0599]:在当前作用域中找不到类型为“Jim”的名为“sleep”的方法
-->src/main.rs:44:9
|
27 |结构吉姆;
|------------找不到此方法的“sleep”
...
44 |吉姆,睡吧();
| ^^^^^
|
=帮助:只有在trait已实现且在范围内时,才能使用trait中的项
=注意:以下特征定义了一个“sleep”项,您可能需要实现它:
候选人#1:`睡觉`
错误[E0599]:在当前作用域中找不到类型为“Jane”的名为“sleep”的方法
-->src/main.rs:47:10
|
34 |结构简体;
|-----找不到此方法的“sleep”
...
47 | jane.sleep();
| ^^^^^
|
=帮助:只有在trait已实现且在范围内时,才能使用trait中的项
=注意:以下特征定义了一个“sleep”项,您可能需要实现它:
候选人#1:`睡觉`
这个编译器错误很奇怪,因为如果一个trait实现另一个trait时出现了问题,我希望在我这么做的时候听到它,而不是在我试图使用结果的程序的最底层
在本例中,只有两种结构和两种睡眠方式,但在一般情况下,有许多结构和几种睡眠方式(但没有结构那么多)
Bed
主要是Sleep
的实现,但在一般情况下Bed
有很多用途,可以实现很多事情
唯一显而易见的方法是将
impl Sleep for…
转换为结构本身使用的宏,但这看起来很粗糙和可怕。您需要为实现第一个特性的对象实现第二个特性:
与
error[E0119]:trait'Sleep'的冲突实现:
-->src/main.rs:24:1
|
10 |/impl T睡眠
11 | |在哪里
12 | | T:哈斯贝德,
13 | | {
... |
16 | | }
17 | | }
||(uu)-这里的第一个实现
...
24 |/impl T睡眠
25 | |在哪里
26 | | T:哈森特,
27 | | {
... |
30 | | }
31 | | }
|| ^冲突的实现
有些东西可以同时实现HasBed和HasTent。如果出现了同时实现了这两种功能的东西,那么代码现在就会变得模棱两可。解决方法是专门化,但目前还没有稳定的实现
你如何实现你的目标?我想你已经提出了当前最好的解决方案——写一个宏。你也可以。宏实际上并没有那么糟糕,但它们可能难以编写
另一件事可能完全基于您为示例选择的名称,就是简单地将结构嵌入到其他结构中,有选择地公开它们。由于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();
}
我们可以在这里使用相关项目
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);
}
测试代码:
fn main() {
let bed = Bed;
let tent = Tent;
let jim = Jim;
let jane = Jane;
jim.sleep(&bed);
jane.sleep(&tent);
}
这(理论上)不能用
usehasbed这样的东西在调用方消除歧义吗代码>?我不知道编译器的详细信息,无法对启用它的复杂程度做出有根据的猜测。@Drew问题不是实现这样的东西,而是从语言设计的角度找到一个理想的设计。在现有的语言限制下,什么是最好的方法?这是一个很好的“你不能这样做”类型的答案,但它并没有真正解决问题的动机。预处理器宏?还有其他设计模式需要考虑吗?@Drew我没有什么好的建议给你,但我更新了,添加了我的建议。既然你已经解决了关于执行特征的特性的高级问题,你也可以考虑问一个单独的下级问题,关于你的实际用例的更多细节。这可能会让比我聪明的人给你答案^_^另见:。也许OP就是那个RFC的作者?
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);
}