Returning different kinds of iterators in flat_map

In the following snippet of code, Rust complains that the return types do not match.

let line = String::new();    // assume string has content
let line: String = line.bytes()
    .flat_map(|b| {
        if b > 0x7F {
            format!("M-{}", char::from(b - 0x7F)).bytes()
        }
        else {
            [b].into_iter()    // error happens here
        }
    })
    .map(|b| { char::from(b) })
    .collect();

The error is the following:

if and else have incompatible types
expected type std::str::Bytes<'_>
found struct std::slice::Iter<'_, u8>

How can this be avoided?

You can use either, wrapping each variant into Left and Right respectively. If you have more than two, you can implement an enum manually, or set Either.

Or you can return Box<dyn Iterator<Item = Whatever>>.

1 Like

I think beyond the first issue (different types returned by the different branches of the if/else there is also a problem with ownership.

In a first attempt I was able to get this to compile:

fn main() {
    let line = String::new(); // assume string has content
    let line: String = line
        .bytes()
        .flat_map(|b| {
            if b > 0x7F {
                format!("M-{}", char::from(b - 0x7F)).into_bytes()
            } else {
                vec![b]
            }
        })
        .map(|b| char::from(b))
        .collect();
}

(Playground)

I think this is probably not the prettiest solution because it allocates intermediate vectors in the loop. It might help you as a compiling starting point, however.

Either helped. Thank you!

Here's a version that doesn't allocate:

fn main() {
    let line = String::from("áÁbBcCeEéÉfF");
    let line: String = line
        .bytes()
        .flat_map(|b| {
            if b > 0x7F {
                Left("M-".bytes().chain(once(b - 0x7F)))
            } else {
                Right(once(b))
            }
        })
        .map(char::from)
        .collect();
        
    println!("{}", line);
}
2 Likes

The auto_enums crate can also be used to create bespoke anonymous enums.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.