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);
}