0

Is it possible to implement a function of fn foo (v: Vec<(String, String)>) -> Vec<(&String, &String)>?

I tried it as v.into_iter().map(|(a, b)| (&a, &b)).collect().

Magicloud
  • 818
  • 1
  • 7
  • 17

2 Answers2

1

I don't think that exact function signature would be possible, because you're not allowed to return references to data owned by the current function, which it would be because the vec was passed by value. But you could do it if you can pass the vec by reference to the conversion function instead (playground):

fn vec_to_vec_ref (strings: &Vec<(String, String)>) -> Vec<(&String, &String)> {
    let mut vec_ref = Vec::new();
    for (a, b) in strings {
        vec_ref.push((a, b));
    }
    vec_ref
}

fn vec_ref (strings: Vec<(&String, &String)>) {
    println!("Success! {:?}", strings);
}

fn main() {
    let strings = vec![(String::from("Foo"), String::from("Bar"))];
    vec_ref(vec_to_vec_ref(&strings));
}
0b10011
  • 18,397
  • 4
  • 65
  • 86
  • [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?](https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-to-a-string-string-vec-vec-o) – Jmb Aug 25 '21 at 06:24
0

You almost got it, simply replace into_iter for iter:

let strings = vec![(String::from("Foo"), String::from("Bar"))]
let strings_refs: Vec<(&String, &String)> = strings.iter().map(|(a, b)| (a, b)).collect();

Playground

With into_iter you are taking the values owned ((String, String)) meanwhile with iter you get a reference to the tuple (&(String, String)), by repacking the inner String references in the map section we get the final target result (&String, &String).

We can expand that to functions, for example, taking an iterator already, or an slice over the data:

fn foo<'a> (v: impl Iterator<Item=&'a(String, String)>) -> Vec<(&'a String, &'a String)> {
    v.map(|(a, b)| (a, b)).collect()
}

fn foo_slice<'a> (v: &'a [(String, String)]) -> Vec<(&'a String, &'a String)> {
    v.iter().map(|(a, b)| (a, b)).collect()
}

Playground

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • This only works in your playground because you use static values. It won't work in the general case (and in particular if you try to encapsulate the code in a function). – Jmb Aug 24 '21 at 07:44
  • @Jmb if you are referring to the fact that with consuming a `Vec` is impossible to safely return a `Vec<&T>` from a function, yes indeed. – Netwave Aug 24 '21 at 08:14
  • Thanks. It does not work in my case. But glad to know the ownership difference between `iter` and `into_iter`. – Magicloud Aug 25 '21 at 05:24