我正在尝试在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
特质具有一个本身返回特质的函数。 What is the correct way to return an Iterator (or any other trait)?将此方法作为一种选择,但我无法实现其他任何一种。如果还有另一种方法可以,那就没问题了。
解决此特定问题有哪些选择?
答案 0 :(得分:2)
如果您明确指定要返回的特征对象(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
生存期限定符添加到任何不合格的trait对象。这意味着编译器会将不合格的Box<dyn MyTrait>
转换为Box<(dyn MyTrait + 'static)>
,这反过来意味着该对象不能包含 any 引用,除非这些引用在整个生命周期中都有效。整个程序。
考虑到这一点,您可以了解为什么self.map.keys()
不符合此严格限制,并且需要更具体的显式限制。