Vec<enum> to Vec<my_type>

I've been trying to think of how to go from Vec<enum> to Vec<my_type>. With the 2 examples below I've tried to demonstrate what I'm trying to do (doesn't run as it isn't exactly legal code).

pub enum Variant{
    Str(String),
    Float(f32),
    Long(i32),
    Bool(bool),
}

fn enum_vec_to_vec(all_variants: Vec<Variant>, wanted_type: Variant) -> Vec<?> {
    let v = vec![];
    for variant in all_variants {
        if let ?WANTED_TYPE? = Variant{
            v.push(l)
        }
    }
    v
}
let all_keydata = vec![Variant::Long(69), Variant::Float(0.0), Variant::Bool(true)];
let vec_with_floats: Vec<f32> = enum_vec_to_vec(all_keydata, Variant::Float);

Or something like this?

fn enum_vec_to_vec<T>(all_variants: Vec<Variant>, wanted_type: u32) -> Vec<T> where T: std::default::Default {
    let mut v = vec![];
    for variant in all_variants {
        match variant {
            Variant::Str(s) if wanted_type == 0 => v.push(s),
            Variant::Float(f) if wanted_type == 1 => v.push(f),
            Variant::Long(l) if wanted_type == 2 => v.push(l),
            Variant::Bool(b) if wanted_type == 3 => v.push(b),
            _ => (),
        }
    }
    v
}

Currently I would probably just create one function per type like so:

fn enum_vec_to_FLOAT_vec(all_variants: Vec<Variant>) -> Vec<f32> {
    let v = vec![];
    for variant in all_variants {
        if let Variant::Float(f) = variant{
            v.push(f)
        }
    }
    v
}

But that seems quite repetetive and so I'm wondering if there would be some more elegant way to do this. It kind of sounds like a generics type of deal, but not able to get it to work.

If this isn't the way to go then I'm also interested in how this type of relation is often dealt with.

You probably could use the filter_map method:

enum_list.iter()
    .filter_map(|item| {
        if let Variant::Float(f) = item {
            Some(f)
        } else {
            None
        }
    })
    .collect::<Vec<_>>()
2 Likes

Infallible type conversions are done by implementing the From trait, and fallible ones with the TryFrom trait.

Iterate through your Vec and convert your types that way.

2 Likes

Some code how that might look:

/*
[dependencies]
derive_more = "0.99.17"
*/

use derive_more::TryInto;

#[derive(TryInto)]
pub enum Variant {
    Str(String),
    Float(f32),
    Long(i32),
    Bool(bool),
}

fn enum_vec_to_vec<Wanted: TryFrom<Variant>>(all_variants: Vec<Variant>) -> Vec<Wanted> {
    all_variants
        .into_iter()
        .filter_map(|x| x.try_into().ok())
        .collect()
}

fn main() {
    let all_keydata = vec![
        Variant::Long(69),
        Variant::Float(0.0),
        Variant::Bool(true),
        Variant::Float(4.2),
    ];
    let vec_with_floats = enum_vec_to_vec::<f32>(all_keydata);
    assert_eq!(vec_with_floats, vec![0.0, 4.2]);
}

Rust Explorer

Edit: I guess, this function could even be made fully generic for all types, not just the enum in question. Or one could get even more generic allowing the input to be all kinds of iterables.

3 Likes

Thank you. Exactly what I was looking for and very clean. Was not quite able to piece it together on my own with the above comments.

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.