25

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);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144

1 Answers1

28

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)

hellow
  • 12,430
  • 7
  • 56
  • 79
  • Yes, it works like a charm! The point was to add something before `collect()` and not after. Very well! But (I am just curious now) what happens if we already have a vector of references? and we want to convert them to vector of values? Should we use `cloned()` in this case too? – Igor Chubin Nov 02 '18 at 09:56
  • 1
    Yes. Thefunction `ret_tup` does exactly that. – hellow Nov 02 '18 at 10:09
  • *This works for every type that implements `Clone`* — perhaps you can show the generic version that literally works for any type that implements `Clone`? – Shepmaster Nov 02 '18 at 12:56
  • @hellow the question and the error *never* matched — OP didn't provide anything that required a value, just showed an error from code they didn't post. – Shepmaster Nov 02 '18 at 13:16
  • 2
    *you can't use `into_iter`* — you can, and the function does own the slice, it just has the same problem. – Shepmaster Nov 02 '18 at 13:20
  • I would appreciate an explanation why the vector iterator iterates over references in the first place. Is that because the values are at the same memory location as the values of the original vector? – lucidbrot Oct 06 '19 at 20:00
  • 1
    @lucidbrot *"the vector iterator iterates over references"*: it doesn't? The slice `iter()` function does. Do you mean that? If yes, the reason is that `into_iter` consumes the `Vec` which is not possible, because you only have a borrowed slice (`&[T]`). You don't own it, therefore you only can iterate over its references. – hellow Oct 07 '19 at 06:23
  • @hellow oh thanks! As a rust newbie, I did not realize [the difference between `iter` and `into_iter`](https://stackoverflow.com/a/34745885/2550406) and I think I read somewhere that they do the same thing, so I just believed that one is old syntax for the other. Your comment helped me :) – lucidbrot Oct 07 '19 at 11:08