Home > Blockchain >  'temporary value dropped while borrowed' when creating Iterator based in condition
'temporary value dropped while borrowed' when creating Iterator based in condition

Time:05-11

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.

  • Related