I am trying to build an Iterator
in Rust that returns the values and indexes of non-null elements in an array. This Iterator
should be reversible based on a bool
parameter.
I managed to build the Iterator
without the reverse condition :
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
However, when trying to build an Iterator
based on a boolean condition (based on this post), I get an error when compiling :
temporary value dropped while borrowed
consider using a let
binding to create a longer lived value 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);
}
}
I have tried cloning the array, or declaring the Iterator
with the let
keyword as suggested by the compiler, but none of it seemed to work. Any idea?
CodePudding user response:
The problem in your code is that you take a reference to a temporary variable.
While trying to fix it, you will have to work around several other issues to do with iterators, such as that using rev()
on one changes its type.
I think your code is best written as something like:
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);
}
}
CodePudding user response:
I found a pretty compact solution using the Either
crate, inspired by this answer.
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
This solution solves the problem mentioned by hkBst (types of an Iterator
and its reverse being different), as well as the original 'temporary value dropped while borrowed' compile error.