簡體   English   中英

無法克隆Vec <Box<Trait> &gt;因為Trait不能成為一個對象

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

我正在嘗試克隆盒裝特征的向量。 當然,簡單地在實現我的特征的所有結構上派生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`

這里是游樂場鏈接,可以輕松運行代碼。

我也嘗試在Sequence a Vec<Box<MusicElement + Clone>>制作elements向量,但這也不起作用。

我無法在網上找到任何有用的解決方案,所以這是我的問題:如何使代碼可以克隆?

解決方案在於結合迄今為止評論中的建議 - @Lukas Kalbertodt的評論中的答案告訴您必須為所有兼容( 'static + MusicElement + Clone )類型創建一個全面的特征實現。 實現所需的唯一后續步驟是將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);
}

編譯,所以它應該足夠了!

我的objekt crate提供了objekt 的答案的可重用實現。 有了它,您可以使您的原始代碼只需最少的更改即可運行。


之前:

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.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM