简体   繁体   English

委派给 HashMap 迭代器时如何消除“预期 &T,找到类型参数”错误?

[英]How to eliminate “expected &T, found type parameter” error when delegating to HashMap iterator?

I'm trying to build a small graph library in Rust.我正在尝试在 Rust 中构建一个小型图形库。 A Graph trait will be implemented by all graphs, and HashGraph is a specific example.一个Graph trait 会被所有的图实现, HashGraph就是一个具体的例子。 HashGraph itself will be a lightweight wrapper around HashMap . HashGraph本身将是HashMap周围的轻量级包装器。

In particular, I want the HashGraph method nodes to return an iterator that delegates next to an underlying iterator obtained from HashGraph#keys .特别是,我希望HashGraph方法nodes返回一个迭代器,该迭代器代表从HashGraph#keys获得的底层迭代器next

Here's my code:这是我的代码:

use std::collections::HashMap;

pub trait Graph<'a, N: 'a> {
    type Nodes: Iterator<Item=&'a N>;

    fn nodes(&'a self) -> Self::Nodes;
}

struct HashGraph<N> {
    map: HashMap<N, ()>
}

impl<N> HashGraph<N> {
    pub fn new(map: HashMap<N, ()>) -> Self {
        HashGraph { map }
    }
}

impl<'a, N: 'a> Graph<'a, &'a N> for HashGraph<N> {
    type Nodes = NodeIterator<'a, &'a N>;

    fn nodes(&'a self) -> Self::Nodes {
        NodeIterator::new(self.map.keys())
    }
}

struct NodeIterator<'a, N> {
    nodes: std::collections::hash_map::Keys<'a, N, ()>
}

impl<'a, N> NodeIterator<'a, N> {
    pub fn new(nodes: std::collections::hash_map::Keys<'a, N, ()>) -> Self {
        NodeIterator { nodes: nodes }
    }
}

impl<'a, N> Iterator for NodeIterator<'a, N> {
    type Item = &'a N;

    fn next(&mut self) -> Option<Self::Item> {
        self.nodes.next()
    }
}

I'm trying to avoid Boxing iterators using the technique described in the answers here .我正在尝试使用此处答案中描述的技术避免装箱迭代器

This code does not compile due to a single error:由于一个错误,此代码无法编译:

   |
23 |         NodeIterator::new(self.map.keys())
   |                           ^^^^^^^^^^^^^^^ expected &N, found type parameter
   |
   = note: expected type `std::collections::hash_map::Keys<'_, &N, _>`
              found type `std::collections::hash_map::Keys<'_, N, _>`

It appears that the HashMap keys iterator isn't returning the expected form of the item, but I'm really unclear how to fix this error.似乎HashMap键迭代器没有返回项目的预期形式,但我真的不清楚如何解决这个错误。 My goal with NodeIterator is to just pass on whatever the HashMap iterator returns for next .我使用NodeIterator的目标是传递HashMap迭代器为next返回的任何内容。

HashGraph should own its keys (the ones in its HashMap ). HashGraph应该拥有它的键(在它的HashMap中的那些)。 Once created, HashGraph will be read-only.一旦创建, HashGraph将是只读的。

The use of HashMap<N, ()> is mainly to simplify the sample code. HashMap<N, ()>的使用主要是为了简化示例代码。 It will ultimately use HashMap<N, HashMap<N, E>> where E is an edge weight.它将最终使用HashMap<N, HashMap<N, E>>其中E是边权重。 Clients would take care of ensuring proper ownership in the HashMap they pass with, for example, reference counting.客户将负责确保他们传递的HashMap的正确所有权,例如引用计数。

How can I modify the sample to eliminate the error and successfully compile?如何修改示例以消除错误并成功编译?

To get the code compiling, you only need to remove a couple of extra & s.要编译代码,您只需要删除几个额外的& s。

use std::collections::HashMap;

pub trait Graph<'a, N: 'a> {
    type Nodes: Iterator<Item = &'a N>;

    fn nodes(&'a self) -> Self::Nodes;
}

struct HashGraph<N> {
    map: HashMap<N, ()>,
}

impl<N> HashGraph<N> {
    pub fn new(map: HashMap<N, ()>) -> Self {
        HashGraph { map }
    }
}

impl<'a, N: 'a> Graph<'a, N> for HashGraph<N> {
    //                   ^^^ this one
    type Nodes = NodeIterator<'a, N>;
    //                           ^^^ and this one

    fn nodes(&'a self) -> Self::Nodes {
        NodeIterator::new(self.map.keys())
    }
}

struct NodeIterator<'a, N> {
    nodes: std::collections::hash_map::Keys<'a, N, ()>,
}

impl<'a, N> NodeIterator<'a, N> {
    pub fn new(nodes: std::collections::hash_map::Keys<'a, N, ()>) -> Self {
        NodeIterator { nodes }
    }
}

impl<'a, N> Iterator for NodeIterator<'a, N> {
    type Item = &'a N;

    fn next(&mut self) -> Option<Self::Item> {
        self.nodes.next()
    }
}

(playground) (操场)

The reasons for this come down to the signatures on the trait Graph and the struct NodeIterator .其原因归结为 trait Graph和 struct NodeIterator上的签名。 When fed Keys<'a, N, ()> , NodeIterator::new returns NodeIterator<'a, N> .当输入Keys<'a, N, ()>时, NodeIterator::new返回NodeIterator<'a, N> However, for your implementation of Graph you want it to return something of type Nodes , which is the type NodeIterator<'a, &'a N> .但是,对于Graph的实现,您希望它返回Nodes类型的东西,即NodeIterator<'a, &'a N>类型。 Notice the extra &'a .注意额外的&'a Moreover, it needs to return an iterator whose items have type &'a N .此外,它需要返回一个迭代器,其项目的类型&'a N Removing some of the &'a s makes everything consistent.删除一些&'a使一切保持一致。

Another solution is to add an extra &'a .另一种解决方案是添加一个额外的&'a

impl<'a, N: 'a> Graph<'a, &'a N> for HashGraph<&'a N> {
    //                                         ^^^ right here
    type Nodes = NodeIterator<'a, &'a N>;

    fn nodes(&'a self) -> Self::Nodes {
        NodeIterator::new(self.map.keys())
    }
}

(playground) (操场)

That would mean that you're consistently using &'a N rather than N itself.这意味着您一直在使用&'a N而不是N本身。

The key here is consistency, but you'll also want to think ahead to how you're going to use these types and traits.这里的关键是一致性,但您还需要提前考虑如何使用这些类型和特征。 Do you want HashGraph to only have references to its keys or own them?您是否希望HashGraph仅引用其键或拥有它们? If they're references, what actually owns them?如果它们是参考,那么实际上拥有它们的是什么? If you use owned keys, are you going to need to move them around a lot?如果您使用自有密钥,您是否需要经常移动它们?

One last thing.最后一件事。 You're using HashMap<N, ()> but, depending on what exactly you're trying to do, HashSet<N> might be more idiomatic.您正在使用HashMap<N, ()>但是,根据您要执行的操作, HashSet<N>可能更惯用。 The two are exactly the same under the hood, but HashSet has a different set of methods that may or may not be more useful for you.两者在底层完全相同,但HashSet有一组不同的方法,它们可能对您更有用,也可能不会。

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

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