mentoc3000
mentoc3000

Reputation: 334

Rust optional iterator default value

I have a custom optional iterator of optional values. If that value is None I would like to provide a default iterator of None values. However, I cannot get the types to match. Below is a reduced example. Any suggestions of how to handle this?

use std::iter;

fn main() {
    let i = Some(vec![Some(1), Some(2), Some(3)]);
    let x = i.unwrap_or(iter::repeat(None).take(3));
    for y in x {
        println!("{:?}", y);
    }
}
   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:5:25
  |
5 |     let x = i.unwrap_or(iter::repeat(None).take(3));
  |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec`, found struct `std::iter::Take`
  |
  = note: expected struct `Vec<Option<{integer}>>`
             found struct `std::iter::Take<std::iter::Repeat<Option<_>>>`

Upvotes: 0

Views: 1020

Answers (1)

Zeta
Zeta

Reputation: 105965

It depends whether x should be an Iterator or a Vec.

Iterator

let x = i.into_iter().flatten().chain(iter::repeat(None)).take(3);

Here's every step explained:

  1. into_iter() creates an iterator from our Option. Our next() call would return the whole Vec.
  2. flatten iterates the Vec and thus all its elements
  3. chain(iter::repeat(None)) adds unlimited Nones to the iteration
  4. take(3) limits the total amount of elements to three.

However, this assumes that you want to have exactly three elements always and either limit the Vec or fill it up with Nones.

Vec

Since take(3) returns an iterator, but unwrap_or returns a Vec on an existing vector, we need to transform the iterator into a Vec via collect():

let x = i.unwrap_or(iter::repeat(None).take(3).collect());

Now the types match.

Upvotes: 1

Related Questions