[英]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()
}
}
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())
}
}
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.