1

我一直在努力理解为什么以下代码的行为方式(Playground):

use std::collections::HashMap;

trait Trait<'a> {
    fn get_enum(&'a self) -> Enum<'a>;
}

#[derive(Clone)]
enum Enum<'a> {
    Arr(Vec<&'a dyn Trait<'a>>),
    Map(HashMap<String, &'a dyn Trait<'a>>)
}

impl<'a> Trait<'a> for Enum<'a> {
    fn get_enum(&'a self) -> Enum<'a> {
        self.clone()
    }
}

fn process<'a>(val: &'a dyn Trait<'a>) -> Vec<&'a dyn Trait<'a>> {
    let mut traits: Vec<&dyn Trait> = vec![];
    match val.get_enum() {
        Enum::Arr(v) => {
            for elem in v {
                traits.push(elem);
            }
        },
        Enum::Map(m) => {
            for elem in m.values() {
                traits.push(elem);
            }
        }
    }
    traits
}

这会引发错误:

error[E0277]: the trait bound `&dyn Trait<'_>: Trait<'_>` is not satisfied
  --> src/main.rs:29:29
   |
29 |                 traits.push(elem);
   |                             ^^^^ the trait `Trait<'_>` is not implemented for `&dyn Trait<'_>`
   |
   = note: required for the cast to the object type `dyn Trait<'_>`

对我来说奇怪的事情并不完全是错误,而是错误只显示来自迭代器HashMap而不是来自Vec迭代器的列表值。有人可以向我解释一下:

  1. 为什么这两个结构的迭代器表现如此不同
  2. 我如何将地图中的值传递到我的数组中

我发现通过get调用检索任何值也会发生同样的现象。

4

1 回答 1

1

区别不在于Vecand HashMap,而在于你如何迭代它们。for循环在IntoIterator内部使用(请参阅为什么通过 `for` 循环遍历集合在 Rust 中被视为“移动”?),因此类型elem取决于可迭代对象。

for elem in v {
    traits.push(elem);
}

Vec<T>实现IntoIterator<Item = T>,所以循环内部elem&'a dyn Trait<'a>.

for elem in m.values() {
    traits.push(elem);
}

HashMap<_, T>::values借来self创建一个Iterator<Item = &T>(实现IntoIterator<Item = &T>)。由于 of 的值类型m已经是一个引用,因此循环内部elem类似于&'b &'a dyn Trait<'a>'b借用的生命周期在哪里m)。

您收到错误的原因the trait bound `&dyn Trait<'_>: Trait<'_>` is not satisfied是因为编译器试图强制 &'b &'a dyn Trait转换为&'b dyn Trait,但它不能因为&'a dyn Trait没有实现Trait. 但即使这样做也不能解决问题——当你试图'b从函数返回生命周期的引用时,你只会得到一个借用错误。

如何将值从我的地图传递到我的数组中?

我在评论中提到您可以按值进行迭代m,这与您正在使用的类似v

for (_key, elem) in m {
    traits.push(elem);
}

这是破坏性的迭代,因为您以后不能使用m。另一个选择,因为共享引用实现Copy,是在你迭代它时将它们复制出地图:

for elem in m.values() {
    traits.push(*elem);          // using * to dereference
}

或者

for &elem in m.values() {        // using & to destructure
    traits.push(elem);
}

这些循环做同样的事情;唯一的区别是elem.

于 2020-06-13T13:41:03.723 回答