简体   繁体   English

如何克隆 Vec <Box<dyn Trait> &gt;?

[英]How can I clone a Vec<Box<dyn Trait>>?

I want to implement a function that takes an immutable &Vec reference, makes a copy, sorts the values and prints them.我想实现一个函数,它接受一个不可变的&Vec引用,制作一个副本,对值进行排序并打印它们。

This is the main code.这是主要代码。

trait Foo {
    fn value(&self) -> i32;
}

struct Bar {
    x: i32,
}

impl Foo for Bar {
    fn value(&self) -> i32 {
        self.x
    }
}

fn main() {
    let mut a: Vec<Box<dyn Foo>> = Vec::new();
    a.push(Box::new(Bar { x: 3 }));
    a.push(Box::new(Bar { x: 5 }));
    a.push(Box::new(Bar { x: 4 }));

    let b = &a;
    sort_and_print(&b);
}

The only way I was able to make it work was this我能够使它工作的唯一方法是这个

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy = Vec::new();
    for val in v {
        v_copy.push(val);
    }
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

However I want to understand what's happening here and also to make the code shorter.但是我想了解这里发生了什么,并使代码更短。

Question 1问题 1

If I try to change let mut v_copy = Vec::new();如果我尝试更改let mut v_copy = Vec::new(); to let mut v_copy: Vec<Box<dyn Foo>> = Vec::new(); let mut v_copy: Vec<Box<dyn Foo>> = Vec::new(); however that results in various errors that I don't know how to fix.但是这会导致我不知道如何修复的各种错误。

How do I make this version work and why is it different than the first version?我如何使这个版本工作,为什么它与第一个版本不同?

Attempt 2尝试 2

Something closer to what I'm looking for is something like this.更接近我正在寻找的东西是这样的。 let mut v_copy = v.clone(); but this doesn't work.但这不起作用。 Can this version be fixed?这个版本可以修复吗?

First, let's annotate the types:首先,让我们注释类型:

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy: Vec<&Box<dyn Foo>> = Vec::new();
    for val /* : &Box<dyn Foo> */ in v {
        v_copy.push(val);
    }
    v_copy.sort_by_key(|o: &&Box<dyn Foo>| <dyn Foo>::value(&***o));
    for val /* : &Box<dyn Foo> */ in v_copy {
        println!("{}", <dyn Foo>::value(&**val));
    }
}

Iterating over &Vec<T> produces an iterator over &T (the same as the .iter() method.迭代&Vec<T>产生一个迭代器&T (与.iter()方法相同。

Now we can see we can convert it into iterator, by either calling .into_iter() on v and then .collect() (which is what the for loop does), or replace into_iter() with iter() (which is more idiomatic since we're iterating over references:现在我们可以看到我们可以将它转换为迭代器,通过在v上调用.into_iter()然后.collect() (这是for循环所做的),或者用iter()替换into_iter() iter() (这更惯用因为我们正在迭代引用:

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy: Vec<&Box<dyn Foo>> = v.iter().collect(); // You can omit the `&Box<dyn Foo>` and replace it with `_`, I put it here for clarity.
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

However, we still only have a copy of the reference ( &Box<dyn Foo> ).但是,我们仍然只有引用的副本( &Box<dyn Foo> )。 Why can't we just clone the vector?为什么我们不能克隆载体?

If we try...如果我们尝试...

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy = v.clone();
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

...the compiler yell at us: ...编译器对我们大喊:

warning: variable does not need to be mutable
  --> src/main.rs:45:9
   |
45 |     let mut v_copy = v.clone();
   |         ----^^^^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0596]: cannot borrow `*v_copy` as mutable, as it is behind a `&` reference
  --> src/main.rs:46:5
   |
45 |     let mut v_copy = v.clone();
   |         ---------- help: consider changing this to be a mutable reference: `&mut Vec<Box<dyn Foo>>`
46 |     v_copy.sort_by_key(|o| o.value());
   |     ^^^^^^ `v_copy` is a `&` reference, so the data it refers to cannot be borrowed as mutable

WHAT???????????什么???????????

Well, let's try to specify the type.好吧,让我们尝试指定类型。 It can make the compiler smarter.它可以使编译器更智能。

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy: Vec<Box<dyn Foo>> = v.clone();
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

Nope.不。

error[E0308]: mismatched types
  --> src/main.rs:45:41
   |
45 |     let mut v_copy: Vec<Box<dyn Foo>> = v.clone();
   |                     -----------------   ^^^^^^^^^
   |                     |                   |
   |                     |                   expected struct `Vec`, found reference
   |                     |                   help: try using a conversion method: `v.to_vec()`
   |                     expected due to this
   |
   = note: expected struct `Vec<Box<dyn Foo>>`
           found reference `&Vec<Box<dyn Foo>>`

Well, let's use the compiler's suggestion:好吧,让我们使用编译器的建议:

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy: Vec<Box<dyn Foo>> = v.to_vec();
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

Grrr!!咕噜!!

error[E0277]: the trait bound `dyn Foo: Clone` is not satisfied
  --> src/main.rs:45:43
   |
45 |     let mut v_copy: Vec<Box<dyn Foo>> = v.to_vec();
   |                                           ^^^^^^ the trait `Clone` is not implemented for `dyn Foo`
   |
   = note: required because of the requirements on the impl of `Clone` for `Box<dyn Foo>`

At least we now have some clues.至少我们现在有了一些线索。

What happened here?这里发生了什么?

Well, like the compiler said, dyn Foo does not implement the Clone trait.好吧,就像编译器说的那样, dyn Foo没有实现Clone特性。 Which means that neither does Box<dyn Foo> , and so is Vec<Box<dyn Foo>> .这意味着Box<dyn Foo>Vec<Box<dyn Foo>>也不行。

However, &Vec<Box<dyn Foo>> actually does impl Clone .然而, &Vec<Box<dyn Foo>>实际上确实impl Clone This is because you can have as many shared references as you want - shared (non-mutable) references are Copy , and every Copy is also Clone .这是因为您可以拥有任意数量的共享引用 - 共享(非可变)引用是Copy ,每个Copy也是Clone Try it:尝试一下:

fn main() {
    let i: i32 = 123;
    let r0: &i32 = &i;
    let r1: &i32 = <&i32 as Clone>::clone(&r0);
}

So, when we write v.clone() , the compiler asks "is there a method named clone() that takes self of type &Vec<Box<dyn Foo>> ( v )?"因此,当我们编写v.clone() ,编译器会询问“是否有一个名为clone()的方法接受&Vec<Box<dyn Foo>> ( v ) 类型的self ?” it first looks for such method on the Clone impl for Vec<Box<dyn Foo>> (because the Clone::clone() takes &self , so for Vec<Box<dyn Foo>> it takes &Vec<Box<dyn Foo>> ).它首先在Clone impl 上为Vec<Box<dyn Foo>>寻找这样的方法(因为Clone::clone()需要&self ,所以对于Vec<Box<dyn Foo>>它需要&Vec<Box<dyn Foo>> )。 Unfortunately, such impl doesn't exist, so it does the magic of autoref (part the process of trying to adjust a method receiver in Rust, you can read more here ), and asks the same question for &&Vec<Box<dyn Foo>> .不幸的是,这样的 impl 不存在,因此它发挥了 autoref 的魔力(尝试在 Rust 中调整方法接收器的过程的一部分,您可以在此处阅读更多内容),并对&&Vec<Box<dyn Foo>>提出同样的问题&&Vec<Box<dyn Foo>> . Now we did find a match - <&Vec<Box<dyn Foo>> as Clone>::clone() !现在我们确实找到了匹配项 - <&Vec<Box<dyn Foo>> as Clone>::clone() So this is what the compiler calls.所以这就是编译器调用的。

What is the return type of the method?方法的返回类型是什么? Well, &Vec<Box<dyn Foo>> .好吧, &Vec<Box<dyn Foo>> This will be the type of v_copy .这将是v_copy的类型。 Now we understand why when we specified another type, the compiler got crazy!现在我们明白为什么当我们指定另一种类型时,编译器会发疯! We can also decrypt the error message when we didn't specify a type: we asked the compiler to call sort_by_key() on a &Vec<Box<dyn Foo>> , but this method requires a &mut Vec<Box<dyn Foo>> ( &mut [Box<dyn Foo>] , to be precise, but it doesn't matter because Vec<T> can coerce to [T] )!当我们没有指定类型时,我们也可以解密错误消息:我们要求编译器在&Vec<Box<dyn Foo>>上调用sort_by_key() ,但是这个方法需要&mut Vec<Box<dyn Foo>>&mut [Box<dyn Foo>] ,准确地说,但这并不重要,因为Vec<T>可以强制转换为[T] )!

We can also understand the warning about a redundant mut : we never change the reference , so no need to declare it as mutable!我们也可以理解关于冗余mut的警告:我们从不更改引用,因此无需将其声明为可变的!

When we called to_vec() , OTOH, the compiler didn't get confused: to_vec() requires the vector's item to implement Clone ( where T: Clone ), which doesn't happen for Box<dyn Foo> .当我们调用to_vec() ,OTOH 时,编译器并没有感到困惑: to_vec()需要向量的项来实现Clonewhere T: Clone ),而Box<dyn Foo>不会发生这种情况。 BOOM.繁荣。

Now the solution should be clear: we just need Box<dyn Foo> to impl Clone .现在解决方案应该很清楚了:我们只需要Box<dyn Foo>来实现Clone

Just?...只是?...

The first thing we may think about is give Foo a supertrait Clone :我们可能会想到的第一件事是给Foo一个 supertrait Clone

trait Foo: Clone {
    fn value(&self) -> i32;
}

#[derive(Clone)]
struct Bar { /* ... */ }

Not working:不工作:

error[E0038]: the trait `Foo` cannot be made into an object
  --> src/main.rs:33:31
   |
33 | fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
   |                               ^^^^^^^ `Foo` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> src/main.rs:1:12
   |
1  | trait Foo: Clone {
   |       ---  ^^^^^ ...because it requires `Self: Sized`
   |       |
   |       this trait cannot be made into an object...

Hmm, looking like indeed Clone requires Sized .嗯,看起来确实Clone需要Sized Why?为什么?

Well, because to clone something, we need to return itself.好吧,因为要克隆某些东西,我们需要返回自身。 Can we return dyn Foo ?我们可以返回dyn Foo吗? No, because it can be of any size.不,因为它可以是任何大小。

So, let's try to impl Clone for Box<dyn Foo> by hand (we can do that even though Box is not defined in our crate because it is a fundamental type).因此,让我们尝试手动impl Clone for Box<dyn Foo> (即使Box未在我们的 crate 中定义,因为它是基本类型,我们也可以这样做)。

impl Clone for Box<dyn Foo> {
    fn clone(self: &Box<dyn Foo>) -> Box<dyn Foo> {
        // Now... What, actually?
    }
}

How can we even clone something that can be anything?我们怎么能克隆一些可以成为任何东西的东西呢? Clearly we need to forward it to someone else.显然,我们需要将其转发给其他人。 Who else?还有谁? Someone who knows how to clone this thing.知道如何克隆这个东西的人。 A method on Foo ? Foo上的方法?

trait Foo {
    fn value(&self) -> i32;
    fn clone_dyn(&self) -> Box<dyn Foo>;
}

impl Foo for Bar {
    fn value(&self) -> i32 {
        self.x
    }
    
    fn clone_dyn(&self) -> Box<dyn Foo> {
        Box::new(self.clone()) // Forward to the derive(Clone) impl
    }
}

NOW!现在!

impl Clone for Box<dyn Foo> {
    fn clone(&self) -> Self {
        self.clone_dyn()
    }
}

IT WORKS!!有用!!

fn sort_and_print(v: &Vec<Box<dyn Foo>>) {
    let mut v_copy = v.clone();
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d6e871711146bc3f34d9710211b4a1dd https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d6e871711146bc3f34d9710211b4a1dd

Note: The dyn-clone crate from @dtonlay generalizes this idea.注意: @dtonlay 的dyn-clone crate 概括了这个想法。

You can make sort_and_print() shorter using Iterator::collect() :您可以使用Iterator::collect()缩短sort_and_print() Iterator::collect()

fn sort_and_print(v: &[Box<dyn Foo>]) {
    let mut v_copy: Vec<_> = v.iter().collect();
    v_copy.sort_by_key(|o| o.value());
    for val in v_copy {
        println!("{}", val.value());
    }
}

Playground 操场

As an aside, accepting a vector by reference is usually better expressed as accepting a slice, as explained here , so the above answer accepts a slice.顺便说一句,通过引用接受矢量通常更好表示为接受片, 按此处的说明,所以上述答案接受片。

You can make it even shorter by using the sorted() method from the itertools crate:您可以使用itertools箱中的sorted()方法使其更短:

use itertools::Itertools;

fn sort_and_print(v: &[Box<dyn Foo>]) {
    for val in v.iter().sorted_by_key(|o| o.value()) {
        println!("{}", val.value());
    }
}

You almost certainly don't want to clone the vector because it would involve a deep copy, ie cloning each Box<dyn Foo> , which is unnecessary, potentially expensive, as well as complicated (as explained in the other answer).您几乎肯定不想克隆向量,因为它会涉及深度复制,即克隆每个Box<dyn Foo> ,这是不必要的,可能很昂贵,而且很复杂(如另一个答案中所述)。

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

相关问题 如何克隆 Vec <Box<dyn SomeTrait> &gt; 在一个物体上? - How can I clone a Vec<Box<dyn SomeTrait>> on an object? 如何移动 Vec <box<dyn trait> &gt; 走进 Vec <rc<refcell<dyn trait> &gt;&gt; </rc<refcell<dyn></box<dyn> - How to move a Vec<Box<dyn Trait>> Into Vec<Rc<RefCell<dyn Trait>>> 如何克隆盒装特征错误(框<dyn error> )?</dyn> - How to clone a boxed trait Error ( Box<dyn Error> )? 你如何转换一个盒子<dyn trait>到 Rc<dyn trait> ?</dyn></dyn> - How do you convert a Box<dyn Trait> to a Rc<dyn Trait>? 创建 Box 时如何转换为 dyn Trait<dyn trait></dyn> - How to cast to dyn Trait when creating a Box<dyn Trait> `Box` 是否掩盖了特征界限? 在这种情况下,为什么我可以将 `dyn FnOnce()` 分配给 `dyn Fn()`? - Does `Box` obscure trait bounds? Why can i assign `dyn FnOnce()` to `dyn Fn()` in this case? 除非我使用临时变量,否则为什么我不能推入 Vec 的 dyn Trait? - Why can't I push into a Vec of dyn Trait unless I use a temporary variable? 无法克隆Vec <Box<Trait> &gt;因为Trait不能成为一个对象 - Can't clone Vec<Box<Trait>> because Trait cannot be made into an object 盒子如何<dyn trait>解构自己?</dyn> - How does Box<dyn Trait> deconstruct itself? 如何为 dyn Trait 对象的 Vec 获取 fmt::Debug 的实现? - How to get an implementation of fmt::Debug for a Vec of dyn Trait objects?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM