Как написать общий итератор, который сохраняет состояние и возвращает значение без использования клона? - PullRequest
0 голосов
/ 23 февраля 2019

Я пытался написать универсальный итератор, но я не вижу, как вернуть значение без использования clone.Есть ли способ создать переменную внутри функции next и вернуть ссылку?Если я заменим T на u32, тогда я смогу просто вернуть Some(self.count), но с использованием дженериков это невозможно.

use num_traits::Num;
use std::clone::Clone;

struct Counter<T>
where
    T: Num + Clone,
{
    count: T,
}

impl<T> Counter<T>
where
    T: Num + Clone,
{
    fn new() -> Counter<T> {
        Counter { count: T::zero() }
    }
}

impl<T> Iterator for Counter<T>
where
    T: Num + Clone,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.count = self.count.clone() + T::one();
        Some(self.count.clone())
    }
}

fn main() {
    let mut number: Counter<u32> = Counter::new();

    match number.next() {
        Some(x) => println!("Number {}", x),
        None => println!("Invalid"),
    }
}

1 Ответ

0 голосов
/ 23 февраля 2019

С одной стороны ... нет, вы не можете заставить итератор возвращать ссылку на значение счетчика.Метод Iterator::next() возвращает значение, которое не имеет связи времени жизни со значением получателя &mut self, поэтому мы не можем контролировать время жизни ссылки, которая будет возвращена там.Это потребуется, потому что мы не можем изменить значение, пока оно заимствовано этой ссылкой.Эту проблему лучше объяснить в другом вопросе .

С другой стороны, , здесь возникает реальная проблема:

Если я заменюT с u32, тогда я могу просто вернуть Some(self.count), но с использованием обобщений это невозможно.

Это только так, потому что u32 реализует Copy, чтоозначает, что он копируется всякий раз, когда это необходимо.Типы, реализующие Copy, также реализуют Clone, что делает примерно то же самое, что и копия, что произошло бы в неуниверсальном контексте.

Таким образом, операции клонирования, которые вы выполняете вэто разумно, так как вы хотите вернуть значение счетчика, все еще имея собственное состояние.Если T этого счетчика представляет собой примитивное целое число, такое как u32, клон такой же дешевый, как и копия этого целого числа.

Кроме этого, вы можете добавить ограничение для T вAddAssign<T>, так что вы можете использовать оператор += для увеличения внутреннего состояния.

impl<T> Iterator for Counter<T> where T: Num + Clone + AddAssign<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.count += T::one();
        Some(self.count.clone())
    }
}

См. Также:

...