How to use filter_map (the Rust equivalent of the F# choose function) properly?

The following snippet does not compile

struct SomeStruct {
    a:usize,
    b:usize
}

fn some_function(some_structs:Vec<SomeStruct>) -> Vec<SomeStruct> { //question update: it is needed for Vec<&SomeStruct>
    some_structs.iter().filter_map(|x|Some(x)).collect()
}

Apparently I need to implement FromIterator for Vec<SomeStruct>. Why can't this be done automatically?

An alternative seems to be to derive Copy and then do this

#[derive(Copy, Clone)]
struct SomeStruct {
    a:usize,
    b:usize
}

fn some_function(some_structs:Vec<SomeStruct>) -> Vec<SomeStruct> {
    some_structs.iter().filter_map(|x|Some(*x)).collect()
}

but then this could get expensive for larger structs right?

Vec's iter() creates an iterator over references (Iterator<Item=&T>). into_iter iterates directly (Iterator<Item=T>). If you use into_iter(), your problem goes away.

struct SomeStruct {
    a:usize,
    b:usize
}

fn some_function(some_structs:Vec<SomeStruct>) -> Vec<SomeStruct> {
    some_structs.into_iter().filter_map(|x|Some(x)).collect()
}

And yes, for very large structs, cloning or copying could become expensive, but you're already traversing the whole Vec - both ways will be O(n), so its unclear how much faster my approach would be.

Just to confirm, into_iter moves the values rather than copying them, right?

Yes, into_iter moves values out of the vector, destroying the vector in the progress. The iter method just provides references.

2 Likes

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.