简体   繁体   English

无法克隆Vec <Box<Trait> &gt;因为Trait不能成为一个对象

[英]Can't clone Vec<Box<Trait>> because Trait cannot be made into an object

I'm trying to clone a vector of boxed traits. 我正在尝试克隆盒装特征的向量。 Naturally simply deriving Clone on all the structs that implement my trait isn't enough, because the compiler doesn't know at compile time that all the structs implementing the trait have Clone . 当然,简单地在实现我的特征的所有结构上派生Clone是不够的,因为编译器在编译时不知道实现该特征的所有结构都具有Clone

Okay, so I then tried to use Clone as a supertrait, but that just lead to the error in the title. 好吧,所以我接着尝试使用Clone作为超级联赛,但这只会导致标题中的错误。 I'm at a loss for solutions. 我对解决方案感到茫然。

Here's the Minimal Working Implementation (or not working, since I can't clone) 这是最小工作实现(或不工作,因为我无法克隆)

#![allow(dead_code, unused_macros)]
use std::fmt::Debug;

trait MusicElement: Debug + Clone {
    fn duration(&self) -> f32;
}

#[derive(Debug, Clone)]
struct Note<'a> {
    name: &'a str,
    duration: f32,
}

impl<'a> MusicElement for Note<'a> {
    fn duration(&self) -> f32 {
        self.duration
    }
}

#[derive(Debug, Clone)]
struct Pause {
    duration: f32,
}

impl MusicElement for Pause {
    fn duration(&self) -> f32 {
        self.duration
    }
}

#[derive(Debug, Clone)]
struct Sequence {
    elements: Vec<Box<MusicElement>>,
}

impl MusicElement for Sequence {
    fn duration(&self) -> f32 {
        self.elements.iter().map(|e| e.duration()).sum()
    }
}

fn main() {
    let a4 = |dur| Box::new(Note { name: "a4", duration: dur });
    let seq = Sequence { elements: vec![a4(0.25), a4(0.25), a4(0.5)] };
    println!("{:?}", seq);
    let seq2 = seq.clone();
    println!("{:?}", seq2);
}

With this error: 出现此错误:

error[E0038]: the trait `MusicElement` cannot be made into an object
  --> src/main.rs:33:5
   |
33 |     elements: Vec<Box<MusicElement>>,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MusicElement` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`

And here's a link to the playground for easy code running. 这里是游乐场链接,可以轻松运行代码。

I've also tried to make the elements vector in Sequence a Vec<Box<MusicElement + Clone>> , but that didn't work either. 我也尝试在Sequence a Vec<Box<MusicElement + Clone>>制作elements向量,但这也不起作用。

I haven't been able to find any useful solutions online, so here's my question: How do I make the code cloneable? 我无法在网上找到任何有用的解决方案,所以这是我的问题:如何使代码可以克隆?

The solution lies in combining the suggestions in the comments thus far - the answer in @Lukas Kalbertodt's comment tells you that you must create a blanket trait implementation for all compatible ( 'static + MusicElement + Clone ) types. 解决方案在于结合迄今为止评论中的建议 - @Lukas Kalbertodt的评论中的答案告诉您必须为所有兼容( 'static + MusicElement + Clone )类型创建一个全面的特征实现。 The only subsequent step necessary for your implementation is changing the Note.name field's type from &'a str to String , as metioned by @Boiethios : 实现所需的唯一后续步骤是将Note.name字段的类型从&'a str更改为String如@Boiethios所述

#![allow(dead_code, unused_macros)]
use std::fmt::Debug;

trait MusicElement: MusicElementClone + Debug {
    fn duration(&self) -> f32;
}

trait MusicElementClone {
    fn clone_box(&self) -> Box<MusicElement>;
}

impl<T: 'static + MusicElement + Clone> MusicElementClone for T {
    fn clone_box(&self) -> Box<MusicElement> {
        Box::new(self.clone())
    }
}

impl Clone for Box<MusicElement> {
    fn clone(&self) -> Box<MusicElement> {
        self.clone_box()
    }
}

#[derive(Debug, Clone)]
struct Note {
    name: String,
    duration: f32,
}

impl MusicElement for Note {
    fn duration(&self) -> f32 {
        self.duration
    }
}

#[derive(Debug, Clone)]
struct Pause {
    duration: f32,
}

impl MusicElement for Pause {
    fn duration(&self) -> f32 {
        self.duration
    }
}

#[derive(Debug, Clone)]
struct Sequence {
    elements: Vec<Box<MusicElement>>,
}

impl MusicElement for Sequence {
    fn duration(&self) -> f32 {
        self.elements.iter().map(|e| e.duration()).sum()
    }
}

fn main() {
    let a4 = |dur| Box::new(Note { name: String::from("a4"), duration: dur });
    let seq = Sequence { elements: vec![a4(0.25), a4(0.25), a4(0.5)] };
    println!("{:?}", seq);
    let seq2 = seq.clone();
    println!("{:?}", seq2);
}

This compiles, so it should suffice! 编译,所以它应该足够了!

My objekt crate provides a reusable implementation of jonny's answer . 我的objekt crate提供了objekt 的答案的可重用实现。 With it you can make your original code work with a bare minimum of changes. 有了它,您可以使您的原始代码只需最少的更改即可运行。


Before: 之前:

trait MusicElement: Debug + Clone {
    fn duration(&self) -> f32;
}

After: 后:

#[macro_use]
extern crate objekt;

trait MusicElement: Debug + objekt::Clone {
    fn duration(&self) -> f32;
}

clone_trait_object!(MusicElement);

// Everything else as you wrote it.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM