Shortcut for partitioning Vec into variables and sub-Vec?

I've hit an awkward use-case where I am receiving from a separate process a list of enums that I need to store in a data model like so:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=44681bab91f06b62b01d5cd14a9e0d72

So I need a result of: (Option<&str>, Option<&str>, Option<&str>, Vec<&str>) given a Vec<Enums>

The above is the best I could come up with because it iterates over the list only once, but it is awkwardly using mutable variables that only should be set once and is returning junk data (Either::Left(None)), which makes me wonder am I missing a more appropriate method for this sort of operation?

Honestly, I would use an ordinary for loop.

I would probably write this without itertools, using a simple loop:

fn attrs(enums: &[Enums]) -> (Option<&str>, Option<&str>, Option<&str>, Vec<&str>) {
    let mut a: Option<&str> = None;
    let mut b: Option<&str> = None;
    let mut c: Option<&str> = None;
    let mut attrs: Vec<&str> = Vec::new();
    
    for r in enums {
        match r {
            Enums::A(i) => a = Some(i),
            Enums::B(i) => b = Some(i),
            Enums::C(i) => c = Some(i),
            Enums::E(i) => attrs.push(i),
        }
    }
    (a, b, c, attrs)
}
1 Like

only downside is now attrs is mut too. Thanks though!

There is really no problem with it being mut.

Pure functional programming is an ingenious trick to show you can code without mutation, but Rust is an even cleverer trick to show you can just have mutation.

Notes on a smaller Rust

I agree with that sentiment and actually pure(-ish?) functional languages fully embrace mutation (e.g. scala). The only thing I like about rust and other language's bias towards immutability is it catches bugs should anyone be changing variables willy nilly, which is otherwise a very hard bug to catch without the compiler's enforcement.

It's also nice not having to pass-through a mut definition everywhere that takes attrs as an arg!

It's not required to thread mut around like this. The mut here is a property of the local variable attrs; it doesn't change the type of the value owned by that variable. You are free to move that value to an immutable variable, take an immutable reference to it, etc.

1 Like

Yeah, notice that mut does not appear anywhere in the return type. The caller of that function does not have to mark them mut. Even in one function, you can just do this:

let attrs = attrs;

This would move the vector to a new immutable binding, shadowing the old one.

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.