Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.try_collect() for Iterator<Option> #951

Open
amab8901 opened this issue May 28, 2024 · 7 comments
Open

.try_collect() for Iterator<Option> #951

amab8901 opened this issue May 28, 2024 · 7 comments
Labels
fallible-iterator Iterator of results/options

Comments

@amab8901
Copy link

.try_collect() is for turning Iterator<Result<T>> into Result<Iterator<T>>. Can you create an equivalent method that turns Iterator<Option<T>> into Option<Iterator<T>>? Or perhaps implement it as a generic, as part of try_collect()?

The use case is for creating programs that never crash at runtime (where error conditions are passed to the logs, and Result converted to Option, and program is continuing without interruption).

@Philippe-Cholet
Copy link
Member

try_collect does not give Result<Iterator> but Result<Vec<...>> (or another container than Vec).

But in #844 we discussed fallible iterators and we might generalize (amongst other things) try_collect (which conflict with nightly Rust) to maybe_collect that would solve your use case.

@Philippe-Cholet Philippe-Cholet added the fallible-iterator Iterator of results/options label May 28, 2024
@amab8901
Copy link
Author

amab8901 commented May 28, 2024

you're right, I missed the Vec part. Here is an example code that would be nice if it worked:

use itertools::Itertools;

fn main() {
    let string: String = [1_u8, 20_u8, 200_u8]
        .iter()
        .map(|u_8| {
            let option_char = if (32..127).contains(u_8) || (160..=255).contains(u_8) {
                let character = char::from(*u_8);
                Some(character)
            } else {
                println!("Error: must be ascii character: `{u_8}`"); // actually tracing::error!() but I wanna keep the example simple
                None
            };

            option_char
        })
        .try_collect()?;

    unreachable!();
}

@Philippe-Cholet
Copy link
Member

Our maybe_collect would merely be a stable Iterator::try_collect, so maybe_collect would eventually be deprecated in favor of it.

@scottmcm
Copy link
Contributor

Can you create an equivalent method that turns Iterator<Option<T>> into Option<Iterator<T>>?

It's literally impossible to make such a method that's lazy.

And if you're fine with Iterator<Option<T>>Option<Vec<T>>, that already exists as collect.

(where error conditions are passed to the logs, and Result converted to Option, and program is continuing without interruption)

Perhaps one of the patterns in https://doc.rust-lang.org/stable/rust-by-example/error/iter_result.html#iterating-over-results would be helpful for you?

@Philippe-Cholet
Copy link
Member

try_collect()? is merely a shortcut for .collect::<Result<_, _>>()?

So yeah, there is .collect::<Option<_>>()? here.

@amab8901
Copy link
Author

I ended up replacing None with Error inside the map, then I used try_collect(), and then I did .map_err() to produce log, then I did .ok()

@Philippe-Cholet
Copy link
Member

That seems more hacky than .collect::<Option<_>>()?.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fallible-iterator Iterator of results/options
Projects
None yet
Development

No branches or pull requests

3 participants