Reputation: 5563
I am defining a trait called ShyAssociation
that returns a lazy iterator of the keys of an associative structure. The iterator should either borrow the keys as immutable or clone them. The keys are always &'static str.
All I need is an iterator that returns &'static str
.
Here is the trait with my attempt at the method for the keys
iterator:
use std::collections::{hash_map::Keys, HashMap};
#[derive(Clone, PartialEq, Debug)]
pub enum ShyValue {
Boolean(bool),
Integer(i64),
Rational(f64),
String(String),
Error(String),
}
pub trait ShyAssociation {
fn keys(&self) -> Keys<&'static str, ShyValue>;
}
impl ShyAssociation for HashMap<&'static str, ShyValue> {
fn keys(&self) -> Keys<&'static str, ShyValue> {
self.keys().cloned()
}
}
It won't compile.
error[E0308]: mismatched types
--> src/lib.rs:18:9
|
18 | self.keys().cloned()
| ^^^^^^^^^^^^^^^^^^^^ expected struct `std::collections::hash_map::Keys`, found struct `std::iter::Cloned`
|
= note: expected type `std::collections::hash_map::Keys<'_, &'static str, _>`
found type `std::iter::Cloned<std::collections::hash_map::Keys<'_, &str, _>>`
UPDATE:
I am attempting a variation on Alexander Huszagh's answer, but have a syntax error:
use std::collections::{hash_map::Keys, HashMap};
#[derive(Clone, PartialEq, Debug)]
pub enum ShyValue {
Boolean(bool),
Integer(i64),
Rational(f64),
String(String),
Error(String),
}
pub trait ShyAssociation<'a> {
fn keys(&self) -> Box<Iterator<Item=&'static str> + 'a>;
}
impl<'a> ShyAssociation<'a> for HashMap<&'static str, ShyValue> {
fn keys(&self) -> Box<Iterator<Item=&'static str> + 'a> {
Box::new<(Iterator<Item=&'static str> + 'a)>(self.keys().cloned())
}
}
The error message is on the "str" in the Iterator Item definition for keys:
expected `:`, found `str`
expected `:`rustc
shy_association.rs(59, 42): expected `:`
Upvotes: 0
Views: 499
Reputation: 14644
The issue is that you're manually specifying a type that doesn't match the return type. iter::Cloned<Keys<_, _>>
is not the same as Keys<_, _>
. A simple fix is to change your return type to iter::Cloned<Keys<&'static str, ShyValue>>
.
pub trait ShyAssociation {
fn keys(&self) -> iter::Cloned<Keys<&'static str, ShyValue>>;
}
impl ShyAssociation for HashMap<&'static str, ShyValue> {
fn keys(&self) -> iter::Cloned<Keys<&'static str, ShyValue>> {
self.keys().cloned()
}
}
If would like to return a type that implements a trait (which will not work in the above example, since this is only valid for non-trait functions and methods), you may also do:
pub fn keys<'a>(hash_map: &'a HashMap<&'static str, ShyValue>) -> impl Iterator<Item = &'a str> {
hash_map.keys().cloned()
}
If you would like to use Box<dyn Iterator>
so you may use it in a trait method, you may do:
pub trait ShyAssociation {
fn keys<'a>(&'a self) -> Box<(dyn Iterator<Item = &'static str> + 'a)>;
}
impl ShyAssociation for HashMap<&'static str, ShyValue> {
fn keys<'a>(&'a self) -> Box<(dyn Iterator<Item = &'static str> + 'a)> {
Box::new(self.keys().cloned())
}
}
The 'a
lifetime is necessary in order to limit the lifetime of the iterator to that of the HashMap
.
Upvotes: 3