this post was submitted on 17 Jan 2022
11 points (92.3% liked)

Rust Programming

8159 readers
1 users here now

founded 5 years ago
MODERATORS
all 8 comments
sorted by: hot top controversial new old
[–] Yujiri@lemmy.ml 6 points 2 years ago (2 children)

Uh... what?

So I understand the type signature she's asking for is Iter<Result<T, E>> -> Result<Iter<T>, Iter<E>>

This suggestion could really use some use case examples. It sounds sufficiently obscure to me that I wouldn't complain about having to write my own a function for this

Also, where does the name evert come from?

[–] Ephera@lemmy.ml 1 points 2 years ago* (last edited 2 years ago) (1 children)

I can see this being useful for parsing. You often want to report all of the parsing errors to the user in one go, so collecting them into a list or iterator is useful.

But yeah, still relatively obscure.

And I'm guessing, "evert" is simply the respective English word: https://en.wiktionary.org/wiki/evert
As a non-native speaker, I didn't know that word either...

[–] Yujiri@lemmy.ml 2 points 2 years ago

I'm a native english speaker and I didn't know that word :o

[–] nutomic@lemmy.ml 3 points 2 years ago (1 children)

I think she is talking about this functionality which already exists. It is not very intuitive though.

let res = my_collection
.iter()
.map(|x| method_that_returns_result(x))
.collect::<Result<Vec<T>, Error>>()?;

So it turns a Vec<Result, Error> into Result<Vec<T>, Error>, and you can turn it into Vec<T> simply with ?. Otherwise you would probably need a for loop.

[–] MadScientist@sopuli.xyz 0 points 2 years ago

do you mean Vec<Result<T, Error>>? why would an error type be the second type argument for a Vec?

[–] asonix@lemmy.ml 1 points 2 years ago* (last edited 2 years ago) (1 children)

i might try

let res = collection.into_iter().map(|item| item.fallible_operation()).fold(Ok(Vec::new()), |acc, res| {
    match (acc, res) {
        (Ok(mut vec), Ok(item)) => {
            vec.push(item);
            Ok(vec)
        (Err(mut vec), Err(error)) => {
            vec.push(error);
            Err(vec)
        }
        (Ok(_), Err(error)) => Err(vec![error]),
        _ => acc,
    }
});

Maybe expand it with

pub trait Evert<T, E> {
    fn evert(self) -> Result<Vec<T>, Vec<E>>;
}

impl<I, T, E> Evert<T, E> for I
where
    I: IntoIterator<Item = Result<T, E>>,
{
    fn evert(self) -> Result<Vec<T>, Vec<E>> {
        self.into_iter().fold(/* implementation from above */)
    }
}

fn main() {
    let result = vec![Ok(1), Err(3), Ok(4), Err(8)].evert();
    assert_eq!(result, Err(vec![3, 8]));
}