How can I convert an Iterator to a tuple (String, String) in an Iterator (& str, & str)?

I am having trouble converting from Iterator (String, String)

to Iterator (&str, &str)

. I am using an external library so I cannot change its signature and not sure what I need. Basically I have a def function:

use hyper;

fn build_url<'a, I>(host: &'a str, port: u16, path: &'a str, params: I) -> 
   hyper::Url where I: Iterator<Item=(String, String)> {

       let mut url = hyper::Url::parse(&format!("http://{h}:{p}/{pt}",
                                            h = self.etcd_host,
                                            p = self.etcd_port,
                                            pt = path));
       if let Err(e) = url {
           panic!("error parsing url: {}", e);
       }

       let mut url = url.unwrap();

       // fn set_query_from_pairs<'a, I>(&mut self, pairs: I)
       //  where I: Iterator<Item=(&'a str, &'a str)>
       url.set_query_from_pairs(
            params.map(|x: (String, String)| -> 
                       (&str, &str) { let (ref k, ref v) = x; (k, v) } ));

}

      

But I get fear: error: 'x.0' does not live long enough

I think the keyword ref

in let should be correct here, i.e. keep ownership of the Iterator and just get busy. I get a similar problem if I get rid of ref

in the question of changing let for this:

let (k, v) = x; (&k, &v)

      

Then k

they v

don't live long enough. Anyone have a recommendation to fix this?

+3


source to share


2 answers


You cannot have an iterator that (safely) links to any internal or state-owned; the symptom is Iterator

simply not meant to resolve it. These types of constructs are commonly referred to as "stream iterators" and are currently a hole in / stdlib.

Consider what happens to the value (String, String)

as it flows through your call map

. Each tuple is returned from I::next

, which causes the property to go to the closure you gave map

. This way, when you use ref

in a closure, you are taking a reference to the variables that are local to the closure. Now you construct a new tuple, return it and ... because the closures are owned String

(they are stored in k

and v

), they are destroyed, which invalidates the references you were trying to return.

The problem is that there is no way to avoid ownership of the elements (String, String)

.



Now that having said, you can cheat here. All you have to do is ensure that the values (String, String)

continue to exist for every single step in the iterator. Thus:

let params: Vec<_> = params.collect();
url.set_query_from_pairs(params.iter().map(|&(ref x, ref y)| (&x[..], &y[..])))

      

It works because it Vec::iter

gives us something Iterator<Item=&(String, String)>

from which we can borrow without ownership (which is preserved params

).

+6


source


Since your argument params

is being created from Vec<(String, String)>

, you can change the where clause to where I: Iterator<Item=(&str, &str)>

and get the iterator by calling

your_vector.iter().map(|(a, b)|, (&a[..], &b[..])))

      



Simplified example:

fn test<'a, I>(it: I)
    where I: Iterator<Item=&'a str>
{
    for s in it {
        dump(s);
    }
}

fn dump(s: &str) {
    println!("{}", s);
}

fn main() {
    let v = vec!["a".to_string(), "42".to_string()];
    test(v.iter().map(|s| &s[..]));
}

      

+2


source







All Articles