12

我正在尝试克隆盒装特征的向量。自然,简单地推导Clone实现我的特征的所有结构是不够的,因为编译器在编译时并不知道所有实现该特征的结构都具有Clone.

好的,然后我尝试将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);
}

出现此错误:

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`

这里是操场的链接,便于代码运行。

我也尝试在a中制作elements矢量,但这也不起作用。SequenceVec<Box<MusicElement + Clone>>

我无法在网上找到任何有用的解决方案,所以这是我的问题:如何使代码可克隆?

4

2 回答 2

11

解决方案在于结合迄今为止评论中的建议 - @Lukas Kalbertodt 评论'static + MusicElement + Clone中的答案告诉您,您必须为所有兼容的 ( ) 类型创建一个全面的特征实现。实现所需的唯一后续步骤是将Note.name字段的类型从更改&'a strString如@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);
}

这编译,所以它应该足够了!

于 2018-04-25T11:19:19.947 回答
3

我的objektcrate 提供了jonny's answer的可重用实现。有了它,您只需最少的更改即可使您的原始代码工作。


前:

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

后:

#[macro_use]
extern crate objekt;

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

clone_trait_object!(MusicElement);

// Everything else as you wrote it.
于 2018-06-10T16:26:33.427 回答