如何从特征实现中返回HashMap的键上的迭代器? [英] How to return an iterator over the keys of a HashMap from a trait implementation?

查看:92
本文介绍了如何从特征实现中返回HashMap的键上的迭代器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Rust中构建一个简单的图形库.任何图都必须实现一个特征 Graph .此特征目前仅具有一个功能,即 nodes ,它允许使用for-in循环来迭代图的节点.

I'm trying to build a simple graph library in Rust. There is a trait Graph that any graph must implement. This trait has only one function at the moment, nodes, which allows iteration of the graph's nodes using a for-in loop.

Graph 的实现, MapGraph ,是围绕 HashMap 的轻量级包装. MapGraph 必须实现 Graph 特征方法 nodes .我在使它正常工作时遇到问题.

An implementation of Graph, MapGraph, is a lightweight wrapper around a HashMap. MapGraph must implement the Graph trait method nodes. I'm having problems getting this to work.

这是 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>>

我找到了与此错误有关的其他参考,但这些情况似乎与我在这里遇到的情况不一样.

I've found other references to this error, but those cases don't seem to look like the one I have here.

我正在使用 Box ,因为 Graph 特性具有一个本身会返回特性的函数.什么是正确的方法返回一个Iterator(或其他任何特征)?将此方法作为一种选择,而我无法实现其他任何一种.如果还有另一种方法可以,那就没问题了.

I'm using Box because the Graph trait has a function that itself returns a trait. What is the correct way to return an Iterator (or any other trait)? gives this approach as one option, and I haven't been able to implement any of the the others. If there's another way to do this, that would be fine.

我可以采取哪些解决方案来解决此特定问题?

What are my options for resolving this specific problem?

推荐答案

如果您明确指定要返回的特征对象( dyn Iterator )包含与生存期相关的引用,则该方法有效 self .

It works if you explicitly specify that the trait object (dyn Iterator) that you are returning contains references that are tied to the lifetime of self.

不添加此限制,编译器无法从函数签名推断出 self 移动或销毁后不能使用迭代器.由于编译器无法推断出这一点,因此它无法安全地在函数的输出中使用 self.map.keys().

Without adding this bound, the compiler cannot infer from the function signature that the iterator cannot be used after self is moved or destroyed. Because the compiler cannot infer this, it cannot safely use self.map.keys() in the function's output.

添加了此限制的工作示例:

Working example with this bound added:

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 "中...

I had thought that a bound of Item = &'a N would also be required, but I guess that's already covered by the "+ '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)> ,这反过来意味着该对象不能包含任何引用,但在整个程序生命周期内均不能使用.考虑到这一点,您可以了解为什么 self.map.keys()不符合此严格限制,并且需要更具体的显式限制.

you have to understand that the compiler, for ergonomic reasons, automatically adds a + 'static lifetime qualifier to any unqualified trait object. This means that an unqualified Box<dyn MyTrait> is transformed by the compiler into a Box<(dyn MyTrait + 'static)>, which in turn means that the object cannot contain any references except those that last for the lifetime of the entire program. With this in mind you can see why self.map.keys() does not fit this strict bound, and a more specific explicit bound is required.

这篇关于如何从特征实现中返回HashMap的键上的迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆