如何克隆存储盒装特征对象的结构? [英] How to clone a struct storing a boxed trait object?

查看:70
本文介绍了如何克隆存储盒装特征对象的结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 性状动物{
fn talk(&self; self ;;
}

struct Dog {
name:String,
}

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

impl狗的动物{
fn说话(和自我){
println!{ {}::! ,self.name};
}
}

struct AnimalHouse {
animal:Box< Animal> ;,
}

fn main(){
let house = AnimalHouse {
动物: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();
}



 错误[E0599]:在当前范围
->中找不到类型为 AnimalHouse的名为 clone的方法; src / main.rs:31:24
|
23 | struct AnimalHouse {
| ------------------未为此
...
31找到方法`clone`。让house2 = house.clone();
| ^^^^^
|
=帮助:特征中的项目只有在实现了特征并且在范围内时才可以使用
=注意:以下特征定义了一个项目克隆,也许您需要实现它:
候选人#1:`std :: clone :: Clone`

我尝试添加#[derive(Clone)] struct AnimalHouse 之前,出现另一个错误:



< pre $ = lang-none prettyprint-override> error [E0277]:限制了动物的特性:std :: clone :: Clone`
-> src / main.rs:25:5
|
25 |动物:Box< Animal>,
| ^^^^^^^^^^^^^^^^^^^^^的特性`std :: clone :: Clone`没有为ʻAnimal`实现。
=注意:必需,因为对std :: boxed :: Box< Animal>的`std :: clone :: Clone`的隐含要求
=注意:`std:必需: :clone :: Clone :: clone`

如何制作结构 AnimalHouse 是否可克隆?通常,通常主动使用特征对象是Rust惯用的吗?

解决方案

存在一些问题。首先,没有什么要求 Animal 也要实现 Clone 。您可以通过更改特征定义来解决此问题:

 特征动物:克隆{
/ * ... * /
}

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



可以要做的是插入一个附加步骤。投身(加上 @ChrisMorgan的评论

 性状动物:AnimalClone {
fn talk(& self);
}

//将AnimalClone拆分为自己的特征使我们能够为所有兼容类型提供全面的
//实现,而不必实现
//动物的其余部分。在这种情况下,我们为所有具有
//静态寿命的类型(*即它们不包含非静态指针)实现它,并且
//实现Animal和Clone。不要问我,当Animal需要AnimalClone时,编译器如何解析
//为Animal实现AnimalClone;我
//不知道为什么会这样。
性状AnimalClone {
fn clone_box(& self)-> Box< Animal>
}

impl< T> T的动物克隆
,其中
T:静态+动物+克隆,
{
fn clone_box(& self)-> Box< Animal> {
Box :: new(self.clone())
}
}

//我们现在可以通过转发到clone_box来手动实现Clone。
impl为Box< Animal>复制{
fn clone(& self)-> Box< Animal> {
self.clone_box()
}
}

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

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

impl狗的动物{
fn talk(& self){
println!( {}:ruff,ruff!,self.name);
}
}

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

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

通过引入 clone_box ,我们可以尝试克隆特征对象来解决这些问题。


I wrote a program that has the trait Animal and the struct Dog implementing the trait. It also has a struct AnimalHouse storing an animal as a trait object 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();
}

It returns "Bobby: ruff, ruff!" as expected, but if I try to clone house the compiler returns errors:

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`

I tried to add #[derive(Clone)] before struct AnimalHouse and got another error:

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`

How do I make the struct AnimalHouse cloneable? Is it idiomatic Rust to use a trait object actively, in general?

解决方案

There are a few problems. The first is that there's nothing to require that an Animal also implements Clone. You could fix this by changing the trait definition:

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

This would cause Animal to no longer be object safe, meaning that Box<Animal> will become invalid, so that's not great.

What you can do is insert an additional step. To whit (with additions from @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 Animal when Animal requires AnimalClone; I
// have *no* idea why this works.
trait AnimalClone {
    fn clone_box(&self) -> Box<Animal>;
}

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

// We can now implement Clone manually by forwarding to clone_box.
impl Clone for Box<Animal> {
    fn clone(&self) -> Box<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<Animal>,
}

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

By introducing clone_box, we can get around the problems with attempting to clone a trait object.

这篇关于如何克隆存储盒装特征对象的结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆