繁体   English   中英

如何从特征实现中返回对 HashMap 的键的迭代器?

[英]How to return an iterator over the keys of a HashMap from a trait implementation?

我正在尝试在 Rust 中构建一个简单的图形库。 任何图都必须实现一个特征Graph 这个特征目前只有一个 function 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特征有一个 function 本身返回一个特征。 返回迭代器(或任何其他特征)的正确方法是什么? 将这种方法作为一种选择,而我无法实现其他任何一种方法。 如果有其他方法可以做到这一点,那很好。

我有哪些解决这个特定问题的选择?

如果您明确指定要返回的特征 object ( dyn Iterator ) 包含与self的生命周期相关的引用,则它可以工作。

如果不添加此绑定,编译器无法从 function 签名中推断出在self移动或销毁后无法使用迭代器。 因为编译器无法推断这一点,所以它不能安全地在函数的 output 中使用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生命周期限定符添加到任何不合格的特征 object。 这意味着编译器将不合格的Box<dyn MyTrait>转换为Box<(dyn MyTrait + 'static)> ,这反过来意味着 object 不能包含任何引用,除了那些持续整个程序的生命周期的引用. 考虑到这一点,您可以看到为什么self.map.keys()不符合这个严格的界限,需要更具体的明确界限。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM