Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the idiomatic way of converting a Vec of references to a Vec of values?

My function returns a Vec of references to a tuple, but I need a Vec of tuples:

use std::collections::HashSet;

fn main() {
    let maxs: HashSet<(usize, usize)> = HashSet::new();
    let mins: HashSet<(usize, usize)> = HashSet::new();
    let intersection = maxs.intersection(&mins).collect::<Vec<&(usize, usize)>>();
}

How should I do the conversion?

Error:

19 |     maxs.intersection(&mins).collect::<Vec<&(usize, usize)>>()
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
   |
   = note: expected type `std::vec::Vec<(usize, usize)>`
          found type `std::vec::Vec<&(usize, usize)>`

I'm using a for loop to do the conversion, but I don't like it and I think there should be a mode idiomatic way:

for t in maxs.intersection(&mins).collect::<Vec<&(usize, usize)>>().iter() {
    output.push(**t);
}
like image 806
Igor Chubin Avatar asked Nov 02 '18 09:11

Igor Chubin


1 Answers

Update from 1.36.0

Rust 1.36.0 introduced copied which works like cloned, but uses the Copy trait, which has the requirement, that the copy is cheap (e.g. a memcpy only). If you have primitive types or types that implement Copy you can use that instead.


To make your example work, use cloned and then collect.

let maxs: HashSet<(usize,usize)> = HashSet::new();
let mins: HashSet<(usize,usize)> = HashSet::new();
let output: Vec<(usize, usize)> = maxs.intersection(&mins).cloned().collect();

This solution will work with any type than implements Clone:

pub fn clone_vec<T: Clone>(vec: Vec<&T>) -> Vec<T> {
    vec.into_iter().cloned().collect()
}

If your function accepts a slice, you have to use cloned twice.

pub fn clone_slice<T: Clone>(slice: &[&T]) -> Vec<T> {
    slice.iter().cloned().cloned().collect()
}

The reason for this is that iter() returns an iterator over references of the slice, which results in &&T.


If you happen to have a type that does not implement Clone, you can mimic the behavior with map

pub struct Foo(u32);

impl Foo {
    fn dup(&self) -> Self {
        Foo(self.0)
    }
}

pub fn clone_vec(vec: Vec<&Foo>) -> Vec<Foo> {
    vec.into_iter().map(|f| f.dup()).collect()
}

pub fn clone_vec2(vec: Vec<&Foo>) -> Vec<Foo> {
    // this function is identical to `clone_vec`, but with another syntax
    vec.into_iter().map(Foo::dup).collect()
}

(playground)

like image 165
hellow Avatar answered Oct 24 '22 00:10

hellow