как реализовать итератор, который делегирует HashMap :: values ​​() - PullRequest
1 голос
/ 20 апреля 2020

Я пытаюсь реализовать структуру данных для хранения «регистров» в группах. Существует основной список, который я считаю владельцем данных реестра.

У меня есть следующие :

use std::collections::hash_map::HashMap;

pub struct Register {
    pub name: String,
    pub address: u16,
}

// map with references to 'master' list of registers
type RegisterMap<'a> = HashMap<String, &'a Register>;

struct RegisterGroup<'a> {
    start_address: u16,
    registers: RegisterMap<'a>,
}

struct RegisterGroupIter<'a> {
    inner: std::collections::hash_map::Values<'a,String,&'a Register>,
}

impl<'a> Iterator for RegisterGroupIter<'a> {
    type Item = &'a Register;
    fn next(&mut self) -> Option<&'a Register> {
        self.inner.next()
    }
}
impl<'a> RegisterGroup<'a> {

    // return iterator over references to Register
    fn registers(&self) -> RegisterGroupIter {
        RegisterGroupIter {
            inner: self.registers.values(),
        }
    }
}

Это разумно / идиоматизм c? Если да, какова правильная настройка для типа элемента в отношении ссылок / продолжительности жизни и т. Д. c? В противном случае, что я должен делать вместо этого?

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:22:9
   |
21 |     fn next(&mut self) -> Option<&'a Register> {
   |                           -------------------- expected `std::option::Option<&'a Register>` because of return type
22 |         self.inner.next()
   |         ^^^^^^^^^^^^^^^^^ expected struct `Register`, found `&Register`
   |
   = note: expected enum `std::option::Option<&'a Register>`
              found enum `std::option::Option<&&'a Register>`

1 Ответ

3 голосов
/ 20 апреля 2020

Поскольку итератор значений HashMap дает ссылки на тип значений, а тип значений в этом случае является самой ссылкой, элементы итератора имеют тип &&Register. Это означает, что вам нужно разыменовать элементы перед возвратом их в ваш итератор. Самый простой способ разыменования внутри параметра - использовать метод copied():

impl<'a> Iterator for RegisterGroupIter<'a> {
    type Item = &'a Register;
    fn next(&mut self) -> Option<&'a Register> {
        self.inner.next().copied()
    }
}

. Я не уверен, почему вы храните имя как ключ карты ha sh и внутри * 1007. * структура. Обычно я пытаюсь нормализовать данные и использовать только имя в качестве ключей карты.

Вам не нужно реализовывать свой собственный тип итератора здесь. Непосредственный возврат значений итератора карты ha sh будет работать нормально:

impl RegisterGroup<'_> {
    fn registers(&self) -> impl Iterator<Item = &Register> {
        self.registers.values().copied()
    }
}
...