Search code examples
rustvectorhashsetvec

Obtaining a Vec<X> from a &HashSet<X>


Assume I have some function do_stuff that takes a &HashSet<X> and wants to collect the items into a Vec<X> by copying all the elements. What is the canonical way to do that? I have basically found the following ways to do this:

  1. Using _.clone().into_iter().collect() (GodBolt Link):

    use std::collections::HashSet;
    
    #[derive(Copy, Clone, Eq, Hash, PartialEq)]
    struct X {}
    
    struct Y {
        xs: HashSet<X>,
    }
    
    fn do_stuff(y: &Y) -> Vec<X> {
        y.xs.clone().into_iter().collect()
    }
    

    This is recommended here:

  2. Using _.iter().cloned().collect() (GodBolt Link):

    use std::collections::HashSet;
    
    #[derive(Copy, Clone, Eq, Hash, PartialEq)]
    struct X {}
    
    struct Y {
        xs: HashSet<X>,
    }
    
    fn do_stuff(y: &Y) -> Vec<X> {
        y.xs.iter().cloned().collect()
    }
    

    This is recommended here:

  3. Using Vec::from_iter(_.iter().cloned()) (GodBolt Link):

    use std::collections::HashSet;
    
    #[derive(Copy, Clone, Eq, Hash, PartialEq)]
    struct X {}
    
    struct Y {
        xs: HashSet<X>,
    }
    
    fn do_stuff(y: &Y) -> Vec<X> {
        Vec::from_iter(y.xs.iter().cloned())
    }
    

    This is recommended here:

I have two questions:

  1. What is the essential difference between the above methods?

  2. What is the canonical way to collect the items from a &HashSet<X> into a Vec<X>?

Related:


Solution

  • _.clone().into_iter().collect()

    This one creates an intermediate copy of HashSet. Which is not something you want, its an unneeded allocation and processing. The rule of thumb is: prefer .cloned() over .clone().

    These two:

    _.iter().cloned().collect()

    Vec::from_iter(_.iter().cloned())

    are equivalent. The first one is more readable IMO.