Vec 和 HashMap 之间的特征对象差异
Trait object discrepancy between Vec and HashMap
我一直在努力理解为什么以下代码会这样运行 (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
的迭代器的列表值这一事实。谁能给我解释一下:
- 为什么两个结构的迭代器表现如此不同
- 如何将地图中的值传递到数组中
我发现同样的现象也发生在通过 get
调用检索任何值时。
区别不在于 Vec
和 HashMap
,而是在于你如何迭代它们。 for
循环在内部使用 IntoIterator
(参见 Why is iterating over a collection via `for` loop considered a "move" in 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>
)。由于 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
,但它不能' t 因为 &'a dyn Trait
没有实现 Trait
。但即使这样做也不能解决问题——当您尝试从函数中 return 生命周期 'b
的引用时,您只会得到一个借用错误。
How I can pass values from my map into my array?
我在评论中提到您可以按值迭代 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
.
的类型
我一直在努力理解为什么以下代码会这样运行 (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
的迭代器的列表值这一事实。谁能给我解释一下:
- 为什么两个结构的迭代器表现如此不同
- 如何将地图中的值传递到数组中
我发现同样的现象也发生在通过 get
调用检索任何值时。
区别不在于 Vec
和 HashMap
,而是在于你如何迭代它们。 for
循环在内部使用 IntoIterator
(参见 Why is iterating over a collection via `for` loop considered a "move" in 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>
)。由于 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
,但它不能' t 因为 &'a dyn Trait
没有实现 Trait
。但即使这样做也不能解决问题——当您尝试从函数中 return 生命周期 'b
的引用时,您只会得到一个借用错误。
How I can pass values from my map into my array?
我在评论中提到您可以按值迭代 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
.