rust - 如何从特征实现中返回 HashMap 键的迭代器?
问题描述
我正在尝试在 Rust 中构建一个简单的图形库。Graph
任何图都必须实现一个特征。这个 trait 目前只有一个函数nodes
,它允许使用 for-in 循环迭代图的节点。
Graph
, ,的实现MapGraph
是一个轻量级的包装器HashMap
。MapGraph
必须实现Graph
trait 方法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
trait 有一个本身返回 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
"...
请注意,要理解以下错误:
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>
编译器将 unqualified 转换为 a Box<(dyn MyTrait + 'static)>
,这反过来意味着对象不能包含任何引用,除了那些持续整个程序生命周期的引用。考虑到这一点,您可以看到为什么self.map.keys()
不符合这个严格的界限,并且需要更具体的明确界限。
推荐阅读
- json - 如何在 Jmeter 中创建动态请求
- python - 在自定义生成器中调整图像大小时出错
- mysql - MySQL max 和 MIN 函数显示 100 及以上作为最小值
- javascript - 如何减小 DOM 的大小?
- 3d - 如何从点云可视化 SHOT(方向直方图的签名)描述符?
- c++-winrt - WinUI3/Desktop/C++: 无法编译 winrt::resume_foreground(Microsoft::System::DispatcherQueue const& dispatcher)
- c# - CEFsharp:告诉网站页面浏览器窗口在整个页面上打开的代码?
- javascript - 有没有办法重写这个基本功能,所以我不会重复两次相同的行?
- jsgrid - 我正在使用 jsGrid,我只想在上一列上按 Enter 后移动下一列
- javascript - HtmlWebpackPlugin 加载多个 HTML 文件并将它们链接到单个脚本 WEBPACK 5