struct - 如何克隆存储盒装特征对象的结构?

标签 struct clone rust traits cloneable

我写了一个程序,它的特征是 Animal和结构 Dog实现特征。它还有一个结构 AnimalHouse将动物存储为特征对象 Box<Animal> .

trait Animal {
    fn speak(&self);
}

struct Dog {
    name: String,
}

impl Dog {
    fn new(name: &str) -> Dog {
        return Dog {
            name: name.to_string(),
        };
    }
}

impl Animal for Dog {
    fn speak(&self) {
        println!{"{}: ruff, ruff!", self.name};
    }
}

struct AnimalHouse {
    animal: Box<Animal>,
}

fn main() {
    let house = AnimalHouse {
        animal: Box::new(Dog::new("Bobby")),
    };
    house.animal.speak();
}

它返回“Bobby:ruff,ruff!”正如预期的那样,但如果我尝试克隆 house编译器返回错误:

fn main() {
    let house = AnimalHouse {
        animal: Box::new(Dog::new("Bobby")),
    };
    let house2 = house.clone();
    house2.animal.speak();
}
error[E0599]: no method named `clone` found for type `AnimalHouse` in the current scope
  --> src/main.rs:31:24
   |
23 | struct AnimalHouse {
   | ------------------ method `clone` not found for this
...
31 |     let house2 = house.clone();
   |                        ^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `clone`, perhaps you need to implement it:
           candidate #1: `std::clone::Clone`

我尝试添加 #[derive(Clone)]之前 struct AnimalHouse并得到另一个错误:

error[E0277]: the trait bound `Animal: std::clone::Clone` is not satisfied
  --> src/main.rs:25:5
   |
25 |     animal: Box<Animal>,
   |     ^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Animal`
   |
   = note: required because of the requirements on the impl of `std::clone::Clone` for `std::boxed::Box<Animal>`
   = note: required by `std::clone::Clone::clone`

如何制作结构 AnimalHouse可克隆?一般而言,主动使用特征对象是惯用的 Rust 吗?

最佳答案

有几个问题。首先是没有什么需要 Animal还实现了 Clone .您可以通过更改特征定义来解决此问题:

trait Animal: Clone {
    /* ... */
}

这会导致 Animal不再是对象安全的,这意味着 Box<dyn Animal>将变得无效,所以这不是很好。

可以做的是插入一个额外的步骤。惠特(添加来自 @ChrisMorgan's comment )。

trait Animal: AnimalClone {
    fn speak(&self);
}

// Splitting AnimalClone into its own trait allows us to provide a blanket
// implementation for all compatible types, without having to implement the
// rest of Animal.  In this case, we implement it for all types that have
// 'static lifetime (*i.e.* they don't contain non-'static pointers), and
// implement both Animal and Clone.  Don't ask me how the compiler resolves
// implementing AnimalClone for dyn Animal when Animal requires AnimalClone;
// I have *no* idea why this works.
trait AnimalClone {
    fn clone_box(&self) -> Box<dyn Animal>;
}

impl<T> AnimalClone for T
where
    T: 'static + Animal + Clone,
{
    fn clone_box(&self) -> Box<dyn Animal> {
        Box::new(self.clone())
    }
}

// We can now implement Clone manually by forwarding to clone_box.
impl Clone for Box<dyn Animal> {
    fn clone(&self) -> Box<dyn Animal> {
        self.clone_box()
    }
}

#[derive(Clone)]
struct Dog {
    name: String,
}

impl Dog {
    fn new(name: &str) -> Dog {
        Dog {
            name: name.to_string(),
        }
    }
}

impl Animal for Dog {
    fn speak(&self) {
        println!("{}: ruff, ruff!", self.name);
    }
}

#[derive(Clone)]
struct AnimalHouse {
    animal: Box<dyn Animal>,
}

fn main() {
    let house = AnimalHouse {
        animal: Box::new(Dog::new("Bobby")),
    };
    let house2 = house.clone();
    house2.animal.speak();
}

通过介绍clone_box ,我们可以通过尝试克隆特征对象来解决问题。

关于struct - 如何克隆存储盒装特征对象的结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30353462/

相关文章:

c++ - 用结构修改 protected 值

c - 声明 C 结构的语法正确方法是什么?

database - 如何使用 Diesel 创建新数据库?

parsing - 如何在 Nom 中解析大写字符串?

c# - 如果数组用作 struct (C#) 中的元素,它存储在哪里?

c - 结构声明

Git 克隆在 Windows bash 中挂起

java - 如何在 Java 中正确复制带有对象的集合

f# - 克隆一个类实例,只更改一些属性

rust - 为什么此生命周期绑定(bind)不会导致错误?