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

Generics 没有为类型'x'实现特性'x'`,generics,compiler-errors,rust,traits,Generics,Compiler Errors,Rust,Traits,编译以下代码时: 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<B

编译以下代码时:

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);
    }
}
错误消息试图说明什么?还有,如何修复它


有一个解决方案,但解决方案是修改trait
a
(在我的例子中,它对应于
Drawable
),但这在这里是不可能的,因为
Drawable
来自外部库。

将固定对象安全规则更新为1.0版本。也就是说,通过value
self
使方法对象不再不安全

发生此错误的原因是

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

  • 它没有
    size
    要求,如
    trait Whatever:size{}
  • 它的所有方法都是对象安全的
  • 如果这两条语句都为true,则方法是对象安全的:

  • 它有
    其中Self:Sized
    要求,如
    fn method()中Self:Sized
  • 以下陈述均不成立:

  • 该方法在签名中以任何形式提及
    Self
    ,即使在引用下,关联类型除外
  • 这种方法是静态的
  • 这种方法是通用的
  • 如果你多想想,这些限制实际上是相当自然的

    请记住,当值被制作成trait对象时,其类型的实际信息会被删除,包括其大小。因此,trait对象只能通过引用使用。引用(或其他智能指针,如
    Box
    Rc
    )在应用于trait对象时,会变成“胖指针”——与指向该值的指针一起,它们还包含指向该值的虚拟表的指针

    由于trait对象只能通过指针使用,因此不能对其调用by value
    self
    方法-您需要实际值才能调用此类方法。这在某一点上违反了对象安全性,这意味着使用这种方法的特征不能成为特征对象,然而,即使在1.0之前,规则已经调整为允许通过值
    self
    方法在特征对象上。但是,由于上述原因,仍然无法调用这些方法。有理由预计,在未来,这一限制将被取消,因为它目前导致了语言中的一些怪癖,例如,无法调用
    Box
    闭包

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

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

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


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


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

    如果您对给定的内容感到困惑,有两个选项可以尝试

    在这种情况下,您不能这样做,但是如果给您一个未指定大小的
    RenderTarget

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

    您可能希望从实现中添加
    ,诸如此类;如果使用它会自动为你实现这些,你会发现更容易。

    < P>我指的是弗拉迪米尔的优秀答案,它解释了对象的安全性,然而,恐怕在讨论的中间,具体的问题被遗忘了。 正如Vladimir所提到的,问题在于类型上的泛型方法(生命周期上的泛型方法很好)使得它所属的特性对于运行时多态性不可用;这在锈蚀中称为物体安全

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

    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);
        }
    }
    
    后者要求
    RenderTarget
    也是对象安全的,因为它现在用于运行时多态情况(因此,没有静态方法,没有泛型方法,没有
    Self
    ,…)

    另一个(更技术性的)区别是前者在编译时是“单纯形的”(也就是说,
    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)
        }
    }
    
    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),
            }
        }
    }
    
    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)