如何 return 从特征实现中迭代 HashMap 的键?
How to return an iterator over the keys of a HashMap from a trait implementation?
我正在尝试用 Rust 构建一个简单的图形库。有一个特征 Graph
是任何图都必须实现的。此特征目前只有一个功能,nodes
,它允许使用 for-in 循环迭代图的节点。
Graph
、MapGraph
的实现是围绕 HashMap
的轻量级包装器。 MapGraph
必须实现 Graph
特征方法 nodes
。我在让它工作时遇到问题。
这是 Graph
的代码:
pub trait Graph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item = &N>>;
}
这里是 MapGraph
的代码:
use std::collections::HashMap;
use crate::rep::Graph;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item=&N>> {
let keys = self.map.keys();
Box::new(keys)
}
}
编译器报错:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:19:29
|
19 | let keys = self.map.keys();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn nodes(&self) -> Box<dyn Iterator<Item = &N>> {
19 | | let keys = self.map.keys();
20 | |
21 | | Box::new(keys)
22 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:19:20
|
19 | let keys = self.map.keys();
| ^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
我发现了其他关于此错误的参考资料,但这些案例似乎与我这里的案例不同。
我正在使用 Box
,因为 Graph
特征具有本身 returns 特征的功能。 What is the correct way to return an Iterator (or any other trait)? 将此方法作为一种选择,而我无法实施其他任何方法。如果有其他方法可以做到这一点。
解决这个具体问题我有哪些选择?
如果您明确指定要返回的特征对象 (dyn Iterator
) 包含与 self
.
的生命周期相关的引用,则它会起作用
如果不添加此绑定,编译器无法从函数签名中推断出在 self
移动或销毁后无法使用迭代器。由于编译器无法推断这一点,因此无法在函数的输出中安全地使用 self.map.keys()
。
添加了此绑定的工作示例:
pub trait Graph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a>;
}
use std::collections::HashMap;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>,
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a> {
let keys = self.map.keys();
Box::new(keys)
}
}
我原以为 Item = &'a N
的界限也是必需的,但我想这已经被“+ 'a
”...
涵盖了
N.B。理解这样的错误:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
您必须了解,出于人体工程学原因,编译器会自动向任何不合格的特征对象添加 + 'static
生命周期限定符。这意味着编译器将不合格的 Box<dyn MyTrait>
转换为 Box<(dyn MyTrait + 'static)>
,这反过来意味着该对象不能包含 任何 引用,除了那些持续整个程序的生命周期。
考虑到这一点,您就会明白为什么 self.map.keys()
不符合这个严格的界限,并且需要更具体的显式界限。
我正在尝试用 Rust 构建一个简单的图形库。有一个特征 Graph
是任何图都必须实现的。此特征目前只有一个功能,nodes
,它允许使用 for-in 循环迭代图的节点。
Graph
、MapGraph
的实现是围绕 HashMap
的轻量级包装器。 MapGraph
必须实现 Graph
特征方法 nodes
。我在让它工作时遇到问题。
这是 Graph
的代码:
pub trait Graph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item = &N>>;
}
这里是 MapGraph
的代码:
use std::collections::HashMap;
use crate::rep::Graph;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes(&self) -> Box<dyn Iterator<Item=&N>> {
let keys = self.map.keys();
Box::new(keys)
}
}
编译器报错:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:19:29
|
19 | let keys = self.map.keys();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn nodes(&self) -> Box<dyn Iterator<Item = &N>> {
19 | | let keys = self.map.keys();
20 | |
21 | | Box::new(keys)
22 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:19:20
|
19 | let keys = self.map.keys();
| ^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
我发现了其他关于此错误的参考资料,但这些案例似乎与我这里的案例不同。
我正在使用 Box
,因为 Graph
特征具有本身 returns 特征的功能。 What is the correct way to return an Iterator (or any other trait)? 将此方法作为一种选择,而我无法实施其他任何方法。如果有其他方法可以做到这一点。
解决这个具体问题我有哪些选择?
如果您明确指定要返回的特征对象 (dyn Iterator
) 包含与 self
.
如果不添加此绑定,编译器无法从函数签名中推断出在 self
移动或销毁后无法使用迭代器。由于编译器无法推断这一点,因此无法在函数的输出中安全地使用 self.map.keys()
。
添加了此绑定的工作示例:
pub trait Graph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a>;
}
use std::collections::HashMap;
pub struct MapGraph<N> {
map: HashMap<N, HashMap<N, ()>>,
}
impl<N> MapGraph<N> {
pub fn new(map: HashMap<N, HashMap<N, ()>>) -> Self {
MapGraph { map }
}
}
impl<N> Graph<N> for MapGraph<N> {
fn nodes<'a>(&'a self) -> Box<dyn Iterator<Item = &N> + 'a> {
let keys = self.map.keys();
Box::new(keys)
}
}
我原以为 Item = &'a N
的界限也是必需的,但我想这已经被“+ 'a
”...
N.B。理解这样的错误:
expected std::boxed::Box<(dyn std::iter::Iterator<Item = &N> + 'static)>
found std::boxed::Box<dyn std::iter::Iterator<Item = &N>>
您必须了解,出于人体工程学原因,编译器会自动向任何不合格的特征对象添加 + 'static
生命周期限定符。这意味着编译器将不合格的 Box<dyn MyTrait>
转换为 Box<(dyn MyTrait + 'static)>
,这反过来意味着该对象不能包含 任何 引用,除了那些持续整个程序的生命周期。
考虑到这一点,您就会明白为什么 self.map.keys()
不符合这个严格的界限,并且需要更具体的显式界限。