Я пытаюсь создать Iterator
в Rust, который возвращает значения и индексы ненулевых элементов в массиве. Это Iterator
должно быть обратимым на основе параметра bool
.
Мне удалось построить Iterator
без условия обратный:
fn main() {
let arr: [u8; 8] = [0, 2, 0, 0, 0, 1, 0, 5];
for (i, x) in arr.iter().enumerate().filter(|(_, &x)| x!=0) {
println!("index: {}, value: {}", i, x);
}
}
>>> index: 1, value: 2
>>> index: 5, value: 1
>>> index: 7, value: 5
Однако при попытке построить Iterator
на основе логического условия (на основе эта почта) я получаю сообщение об ошибке при компиляции:
временное значение упало при заимствовании
рассмотрите возможность использования привязки let
для создания более долговечной ценности rustc(E0716)
.
fn main() {
// Array to observe
let arr: [u8; 8] = [0, 2, 0, 0, 0, 1, 0, 5];
// Reverse parameter
let reverse: bool = true;
// Building Iterator based on `reverse` parameter
let iter: &mut dyn Iterator<Item = (usize, &u8)> = match reverse {
// forward Iterator
false => {
&mut arr.iter().enumerate().filter(|(_, &x)| x!=0)
}
// Reversed iterator
true => {
&mut arr.iter().enumerate().filter(|(_, &x)| x!=0).rev()
}
};
// Print indices and values of non 0 elements in the array
for (i, x) in iter {
println!("index: {}, value: {}", i, x);
}
}
Я попытался клонировать массив или объявить Iterator
с ключевым словом let
, как было предложено компилятором, но ничего из этого не сработало. Есть идеи?
Проблема в вашем коде в том, что вы берете ссылку на временную переменную.
При попытке исправить это вам придется обойти несколько других проблем, связанных с итераторами, например, использование rev()
для изменения его типа.
Я думаю, что ваш код лучше всего написать примерно так:
use std::fmt::Display;
fn main() {
// Array to observe
let arr: [u8; 8] = [0, 2, 0, 0, 0, 1, 0, 5];
// Reverse parameter
let reverse: bool = true;
// Building Iterator
let iter = arr.iter().enumerate().filter(|(_, &x)| x != 0);
// Print indices and values of non 0 elements in the array
if reverse {
print_iter(iter.rev());
} else {
print_iter(iter);
}
}
fn print_iter<I: Display, T: Display>(iter: impl Iterator<Item = (I, T)>) {
for (i, x) in iter {
println!("index: {}, value: {}", i, x);
}
}
Я нашел довольно компактное решение, используя ящик Either
, вдохновленный этот ответ.
extern crate either;
use either::Either;
fn main() {
// Array to observe
let arr: [u8; 8] = [0, 2, 0, 0, 0, 1, 0, 5];
// Reverse parameter
let reverse: bool = true;
// Pick the right iterator based on reverse
let iter = match reverse {
true => Either::Left(arr.iter().enumerate().filter(|(_, &x)| x!=0).rev()),
false => Either::Right(arr.iter().enumerate().filter(|(_, &x)| x!=0))
};
// Print indices and values of non 0 elements in the array
for (i, x) in iter {
println!("index: {}, value: {}", i, x);
}
}
>>> index: 7, value: 5
>>> index: 5, value: 1
>>> index: 1, value: 2
Это решение решает проблему, упомянутую hkBst (типы Iterator
и его реверса разные), а также исходную ошибку компиляции «временное значение упало при заимствовании».
Вы можете решить эту проблему, объявив переменные для хранения временных объектов за пределами оператора
match
, так же, как здесь: детская площадка.