我为另一个 trait 实现了一个 trait,但不能从这两个 trait 调用方法 [英] I implemented a trait for another trait but cannot call methods from both traits

查看:24
本文介绍了我为另一个 trait 实现了一个 trait,但不能从这两个 trait 调用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个叫做 Sleep 的特性:

I have a trait called Sleep:

pub trait Sleep {
    fn sleep(&self);
}

我可以为每个结构体提供不同的 sleep 实现,但事实证明,大多数人的睡眠方式非常少.你可以睡在床上:

I could provide a different implementation of sleep for every struct, but it turns out that most people sleep in a very small number of ways. You can sleep in a bed:

pub trait HasBed {
    fn sleep_in_bed(&self);
    fn jump_on_bed(&self);
}

impl Sleep for HasBed {
    fn sleep(&self) {
        self.sleep_in_bed()
    }
}

如果你在露营,你可以睡在帐篷里:

If you're camping, you can sleep in a tent:

pub trait HasTent {
    fn sleep_in_tent(&self);
    fn hide_in_tent(&self);
}

impl Sleep for HasTent {
    fn sleep(&self) {
        self.sleep_in_tent()
    }
}

有一些奇怪的情况.我有一个可以靠墙睡觉的朋友,但大多数人在大多数情况下都会陷入一些简单的情况.

There are some oddball cases. I have a friend that can sleep standing against a wall, but most people, most of the time, fall into some simple case.

我们定义了一些结构体并让它们休眠:

We define some structs and let them 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[E0599]: no method named `sleep` found for type `Jim` in the current scope
  --> src/main.rs:44:9
   |
27 | struct Jim;
   | ----------- method `sleep` not found for this
...
44 |     jim.sleep();
   |         ^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `sleep`, perhaps you need to implement it:
           candidate #1: `Sleep`

error[E0599]: no method named `sleep` found for type `Jane` in the current scope
  --> src/main.rs:47:10
   |
34 | struct Jane;
   | ------------ method `sleep` not found for this
...
47 |     jane.sleep();
   |          ^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `sleep`, perhaps you need to implement it:
           candidate #1: `Sleep`

这个编译器错误很奇怪,因为如果一个 trait 实现另一个 trait 有问题,我希望在我这样做的时候听到它,而不是在我尝试使用结果时在程序的最底部.

This compiler error is strange because if there was something wrong with a trait implementing another trait, I expected to hear about it way back when I did that, not at the very bottom of the program when I try to use the result.

在这个例子中,只有2个结构体和2种睡眠方式,但一般情况下有很多结构体和几种睡眠方式(但没有结构体那么多).

In this example, there are only 2 structs and 2 ways to sleep, but in the general case there are many structs and several ways to sleep (but not as many ways as there are structs).

Bed 主要是 Sleep 的实现,但在一般情况下,Bed 有很多用途,可以实现很多东西.

A Bed is mostly an implementation for Sleep, but in the general case a Bed has many uses and could implement many things.

唯一显而易见的方法是将 impl Sleep for... 转换为一个结构体自己使用的宏,但这看起来很笨拙和可怕.

The only immediately obvious approach is to convert impl Sleep for... into a macro that structs themselves use, but that seems hacky and terrible.

推荐答案

您需要为实现第一个特征的对象实现第二个特征:

You need to implement the second trait for objects that implement the first trait:

impl<T> Sleep for T
where
    T: HasBed,
{
    fn sleep(&self) {
        self.sleep_in_bed()
    }
}

以前,您正在为特征的类型实现 Sleep,更好地表示为 dyn HasBed.请参阅dyn"是什么?是指类型吗?了解更多详情.

Previously, you were implementing Sleep for the trait's type, better expressed as dyn HasBed. See What does "dyn" mean in a type? for more details.

但是,一旦您添加第二个全面实现,这就会中断:

However, this is going to break as soon as you add a second blanket implementation:

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:24:1
   |
10 | / impl<T> Sleep for T
11 | | where
12 | |     T: HasBed,
13 | | {
...  |
16 | |     }
17 | | }
   | |_- first implementation here
...
24 | / impl<T> Sleep for T
25 | | where
26 | |     T: HasTent,
27 | | {
...  |
30 | |     }
31 | | }
   | |_^ conflicting implementation

可以实现两者 HasBedHasTent.如果出现同时实现了两者的东西,那么代码现在将是模棱两可的.解决这个问题的方法是专业化,但目前还没有稳定的实现.

It's possible for something to implement both HasBed and HasTent. If something were to appear that implemented both, then the code would now be ambiguous. The workaround for this would be specialization, but there's no stable implementation of that yet.

你如何实现你的目标?我认为您已经建议了当前的最佳解决方案 - 编写宏.您也可以编写自己的派生宏.宏确实没有那么糟糕,但它们编写起来可能很笨拙.

How do you accomplish your goal? I think you have already suggested the current best solution - write a macro. You could also write your own derive macro. Macros really aren't that bad, but they can be unwieldy to write.

另一件事,可能完全基于您为示例选择的名称,将简单地将结构嵌入到其他结构中,可选择将它们设为公开.由于您对 Sleep 的实现基本上只依赖于床/帐篷,因此这样做不会丢失任何功能.当然,有些人可能会觉得这打破了封装.您可以再次创建宏来实现各种委托.

Another thing, which may be entirely based on the names you chose for your example, would be to simply embed structs into other structs, optionally making them public. Since your implementation of Sleep basically only depends on the bed / tent, no functionality would be lost by doing this. Of course, some people might feel that breaks encapsulation. You could again create macros to implement a delegation of sorts.

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

这篇关于我为另一个 trait 实现了一个 trait,但不能从这两个 trait 调用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆