当前位置: 首页 > 知识库问答 >
问题:

没有为类型'x'实现特性'x'`

邓建柏
2023-03-14

编译以下代码时:

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);
                         ^~~~~~~~~~~~~~

错误消息试图说明什么?还有,怎么修?

有一个相关的问题,但解决方案是修改特征<code>a</code>(在我的例子中对应于<code>可绘制</code>),但这在这里是不可能的,因为<code>可以绘制</code>来自外部库。

共有3个答案

爱海
2023-03-14

如果你坚持你所得到的,有两种选择可以尝试。

在这种情况下,您不能,但如果您获得一个未调整大小的RenderTarget

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

你可以实现

trait DrawableDynamic {
    fn draw(&self, target: &mut RenderTarget);
}

impl<T: Drawable> DrawableDynamic for T {
    fn draw(&self, target: &mut RenderTarget) {
        Drawable::draw(self, target)
    }
}

将您获得的类型重定向到对象安全的动态调度替代项。看起来这样的更改可以在上游进行,因为您无法真正使用RT大小的事实。

另一个不允许您在< code>Vec中放置任意的< code>Drawable,但是应该可以在不允许上游未调整大小的类型的情况下工作。这是使用枚举来包装向量的可能值:

enum AllDrawable {
    Square(Square),
    Triangle(Triangle)
}

impl Drawable for AllDrawable {
    fn draw<RT: RenderTarget>(&self, target: &mut RT) {
        match *self { 
            AllDrawable::Square(ref x) => x.draw(target),
            AllDrawable::Triangle(ref x) => x.draw(target),
        }
    }
}

人们可能想要添加From实现等;如果使用wrapped_enum!会自动为您实现这些,您可能会发现更容易。

公西嘉玉
2023-03-14
匿名用户

我指的是弗拉基米尔精彩的回答,它解释了物体的安全性,但是我担心在讨论的过程中,手头的具体问题被遗忘了。

正如 Vladimir 所提到的,问题在于,一个泛型类型的方法(泛型在生存期内是好的)使得它所属的特征对于运行时多态性不可用;这在 Rust 中称为对象安全。

因此,最简单的修复方法是删除方法的泛型参数!

trait RenderTarget {}

struct RenderWindow;
impl RenderTarget for RenderWindow {}

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

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

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

之间的主要区别:

fn draw<RT: RenderTarget>(&self, target: &mut RT)

fn draw(&self, target: &mut RenderTarget)

后者要求<code>RenderTarget</code>也是对象安全的,因为它现在用于运行时多态情况(因此,没有静态方法,没有泛型方法,没有<code>Self</code>,…)。

另一个(更技术性的)区别是,前者在编译时是“单形化的”(即< code>RT被替换为实类型并应用了所有相关的优化),而后者不是(因此,不会发生这样的优化)。

澹台宾白
2023-03-14

更新:将对象安全规则固定到1.0版本。也就是说,按值自我使方法对象不再不安全。

发生此错误是由于对象安全。

为了能够从特征中创建特征对象,特征必须是对象安全的。如果这两条语句都成立,则特征是对象安全的:

  1. 它没有大小要求,如在特征中 无论什么:大小{};
  2. 它的所有方法都是对象安全的。

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

>

  • 它具有其中Self:大小要求,如fn方法()中,其中Self:大小;
  • 以下任何陈述均不成立:

    1. 此方法以任何形式在其签名中提及Self,即使在引用下,关联类型除外;
    2. 此方法是静态的;
    3. 此方法是通用方法。

    如果你多想想,这些限制实际上是相当自然的。

    请记住,当将值制成trait对象时,它们类型的实际信息(包括它们的大小)会被擦除。因此,trait对象只能通过引用使用。当应用于trait对象时,引用(或其他智能指针,如BoxRc)成为“胖指针”-连同指向值的指针,它们还包含指向该值的虚拟表的指针。

    由于 trait 对象只能通过指针使用,因此不能在它们上调用按值 self 方法 - 您需要实际值才能调用此类方法。这一点违反了对象安全,这意味着具有此类方法的特征不能成为特征对象,但是,即使在1.0之前,规则也已进行调整,以允许在特征对象上使用按值的自我方法。但是,由于上述原因,仍然无法调用这些方法。有理由期望将来会取消此限制,因为它目前会导致语言中的一些怪癖,例如,无法调用Box。

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

    为什么静态方法不能在特征对象上调用,我想,是显而易见的 - 静态方法从定义上“属于”特征本身,而不是值,所以你需要知道实现特征的具体类型来调用它们。更具体地说,常规方法通过存储在特征对象内的虚拟表进行调度,但静态方法没有接收器,因此它们没有要调度的内容,因此它们不能存储在虚拟表中。因此,在不知道具体类型的情况下,它们是不可调用的。

    泛型特征方法不能被调用还有另一个原因,我认为更多的是技术而不是逻辑。在Rust中,泛型函数和方法是通过单态化实现的——也就是说,对于具有一组具体类型参数的泛型函数的每个实例化,编译器都会生成一个单独的函数。对于语言用户来说,他们似乎在调用泛型函数;但在每组类型参数的最低级别上,都有一个单独的函数副本,专门用于实例化类型。

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

    如果Drawable是一个外部特征,那么您就被卡住了——不可能做你想做的,也就是说,对异构集合中的每个项目调用Drawable()。如果您的可绘制对象集是静态已知的,您可以为每个可绘制类型创建一个单独的集合,或者创建您自己的enum,它将包含您拥有的每个可绘制类型的变体。然后您可以为枚举本身实现Drawable,这将非常简单。

  •  类似资料:
    • 我希望这能奏效: ...但它没有: 游戏Geofence:http://is.gd/kxDt0P 那么,发生了什么事? 我不知道这个错误是什么意思。 是因为我使用的是Result,而这要求U,V不是大小的吗?在这种情况下,它们的尺寸为何?我没有写: 所有泛型现在都是动态调整大小还是什么?(在这种情况下,大小是什么?甚至是什么意思?) 怎么回事啊?

    • 我已经搜索了很多页,但没有找到答案,所以我粘贴了整个代码。我正在测试测试类,并得到这样的错误:“起因:org.springframework.beans.factory.BeanCreation异常:创建名为“userRepository”的bean时出错:初始化方法调用失败;嵌套异常java.lang.IllegalArgument异常:未能为方法公共抽象创建查询org.home.mysyste

    • 您好,我正在建立一个动物园微服务,包括动物、员工、客户和价格表。我的动物微服务可以工作,但在我的员工微服务中,我遇到了一个错误,即没有为类型“EmployeeModel”找到属性“name”。在问这个问题之前,我已经在网上搜索了几个小时,还有一些类似的问题。我在模型中没有“名字”employee_name,我只是感到困惑,不知道如何修复它。任何指导/建议/信息将不胜感激:)第一次发布,所以我希望我

    • 我觉得很烦人。因此,我想知道是否可以直接为Function1从类型变量a到Boolean定义predicateContra,而不是使用类型别名,但我无法使其工作。以下两种想法都给了我一个编译器错误: 我如何告诉编译器我的Function1的第一个参数应该保持一个“hole”,而第二个应该固定为boolean?有可能吗?在查看cats的源代码时,我发现星号在很多地方作为类型参数,但这对我也不起作用。

    • 我有一个枚举类角色类型 在我的实体类中,我有枚举集合的以下映射。这是代码: 我将这个用户实体类转换为Kotlin,下面是代码: 转换后,hibernate抛出以下异常: 它以前在Java工作得很好。 我还尝试在中添加,如下所示: 但这也是另一个例外。 注意:如果我将角色的修饰符从var改为val,它可以工作,但我需要它是一个可变类型。我不理解字段的易变性如何在hibernate中产生问题。 注意: