特性`x`不是为类型`x`实现的 [英] Trait `x` is not implemented for the type `x`

查看:170
本文介绍了特性`x`不是为类型`x`实现的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编译以下代码时:

trait RenderTarget {}

struct RenderWindow;
impl RenderTarget for RenderWindow {}

trait Drawable {
    fn draw<RT: RenderTarget>(&self, target: &mut RT);
}

fn main() {
    let mut win = RenderWindow;
    let mut vec: Vec<Box<Drawable>> = Vec::new();

    for e in &vec {
        e.draw(&mut win);
    }
}

我得到错误:

error: the trait `Drawable` is not implemented for the type `Drawable` [E0277]
src/main.rs:15         e.draw(&mut win);
                         ^~~~~~~~~~~~~~

错误信息试图告诉?此外,如何解决此问题?

What is the error message trying to tell? Also, how to fix it?

有一个相关问题但是解决方案是修改trait A (对应于 Drawable 在我的case),但是这是不可能的因为 Drawable 来自外部库。

There's a related question but the solution there was to modify the trait A (which corresponds to Drawable in my case), but that's not possible here since Drawable is from an external library.

推荐答案

更新:固定对象安全规则到1.0版本。也就是说,by-value self 使方法对象不安全不再。

Update: fixed object safety rules to the 1.0 version of them. Namely, by-value self makes method object-unsafe no longer.

=http://huonw.github.io/blog/2015/01/object-safety/ =nofollow>对象安全。

This error happens because of object safety.

为了能够从trait中创建一个trait对象,trait必须是对象安全的。如果这两个语句都具有对象安全性,则trait是对象安全的:

In order to be able to create a trait object out of a trait, the trait must be object-safe. A trait is object-safe if both of these statements hold:


  1. 它没有大小需求,如 trait Whatever:Sized {} ;

  2. 所有的方法都是对象安全的。
  1. it does not have Sized requirement, as in trait Whatever: Sized {};
  2. all its methods are object-safe.

如果这两个语句都为真,则方法是对象安全的:

A method is object-safe if both of these statements are true:


  1. 它具有其中Self:Sized 需求,如 fn method()其中Self:Sized

  2. 以下所有语句均不成立:

  1. it has where Self: Sized requirement, as in fn method() where Self: Sized;
  2. none of the following statements holds:


  1. 此方法提及<$ c $

  2. 此方法是静态的;

  3. 此方法是通用的。


请记住,当值被赋予trait对象时,它们的类型的实际信息被删除,包括它们的大小。因此,trait对象只能通过引用来使用。引用(或其他智能指针,如 Box Rc )应用于trait对象时, - 连同指向该值的指针,它们还包含指向该值的虚拟表的指针。

Remember that when values are made into trait objects, actual information of their type is erased, including their size. Therefore, trait objects can only be used through a reference. References (or other smart pointers, like Box or Rc), when applied to trait objects, become "fat pointers" - along with the pointer to the value, they also contain a pointer to the virtual table for that value.

由于trait对象只能通过指针使用,值 self 方法不能被调用他们 - 你需要实际的值,以便调用这样的方法。这是一个对象安全的违反,这意味着使用这样的方法的特征不能作为trait对象,然而,即使在1.0之前,规则已被调整为允许by-value self 对trait对象的方法。然而,由于上述原因,这些方法仍然不能被调用。有理由期望在将来这个限制将被取消,因为它目前导致语言中的一些怪癖,例如,无法调用 Box closures。

Because trait objects can only be used through a pointer, by-value self methods can't be called on them - you'd need the actual value in order to call such methods. This was a violation of object safety at one point, which meant that traits with such methods couldn't be made trait objects, however, even before 1.0 the rules had been tweaked to allow by-value self methods on trait objects. These methods still can't be called, though, due to the reason described above. There are reasons to expect that in the future this restriction will be lifted because it currently leads to some quirks in the language, for example, the inability to call Box<FnOnce()> closures.

Self 不能用于应该在trait对象上调用的方法,因为trait对象的实际类型已被擦除,但是为了调用这样的方法,编译器需要知道这个已擦除的类型。

Self can't be used in methods which should be called on trait objects precisely because trait objects have their actual type erased, but in order to call such methods the compiler would need to know this erased type.

为什么静态方法不能在trait对象上调用,我想,很明显 - 静态方法通过定义属于trait本身,而不是值,所以你需要知道具体类型实现trait来调用它们。更具体地,常规方法通过存储在trait对象内的虚拟表来分派,但是静态方法没有接收者,所以它们没有任何分发,因此它们不能存储在虚拟表中。因此,他们不知道具体的类型是不可能的。

Why static methods can't be called on trait objects, I guess, is obvious - static methods by definition "belong" to the trait itself, not to the value, so you need to know the concrete type implementing the trait to call them. More concretely, regular methods are dispatched through a virtual table stored inside a trait object, but static methods do not have a receiver, so they have nothing to dispatch on, and for this reason they can't be stored in a virtual table. Thus they are uncallable without knowing the concrete type.

一般trait方法不能被调用另一个原因,更多的技术比逻辑,我想。在Rust中,泛型函数和方法通过单形式化实现 - 也就是说,对于具有一组具体类型参数的泛型函数的每个实例化,编译器生成一个单独的函数。对于语言用户,它看起来像是在调用通用函数;但在每个类型参数的最低级别有一个单独的函数副本,专门为实例化的类型工作。

Generic trait methods can't be called for another reason, more technical than logical, I think. In Rust generic functions and methods are implemented through monomorphization - that is, for each instantiation of a generic function with a concrete set of type parameters the compiler generate a separate function. For the language user it looks like that they're calling a generic function; but on the lowest level for each set of type parameters there is a separate copy of the function, specialized to work for the instantiated types.

给定这种方法,为了在一个trait对象上调用泛型方法,你需要它的虚拟表包含指向所有可能类型的泛型方法的几乎每个可能的实例化的指针,这当然是不可能的,因为它将需要无限实例化数量。因此不允许在trait对象上调用泛型方法。

Given this approach, in order to call generic methods on a trait object you would need its virtual table to contain pointers to virtually each and every possible instantiation of the generic method for all possible types, which is, naturally, impossible because it would require infinite number of instantiations. And so calling generic methods on trait objects is disallowed.

如果 Drawable 是外部特性,卡住 - 这是不可能做你想要的,也就是调用 draw()在异构集合中的每个项目。如果你的绘图集是静态已知的,你可以为每个绘图类型创建一个单独的集合,或者,创建自己的枚举,其中包含每个可绘制类型的变体有。然后你可以为枚举本身实现 Drawable ,这将是相当直接。

If Drawable is an external trait, then you're stuck - it is impossible to do what you want, that is, to call draw() on each item in a heterogeneous collection. If your set of drawables is statically known, you can create a separate collection for each drawable type or, alternatively, create your own enum which would contain a variant for each drawable type you have. Then you can implement Drawable for the enum itself, which would be fairly straightforward.

这篇关于特性`x`不是为类型`x`实现的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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