简体   繁体   中英

How may I return an iterator over the keys of a HashMap that clones the keys?

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 `:`

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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