I'm having trouble converting from an Iterator of (String, String)
to an Iterator of (&str, &str)
. I'm using an external library, so can't change the signature of that, and not sure that I need to. Basically I have this function def:
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'm getting the dreaded: error: 'x.0' does not live long enough
I think the ref
keyword in the let should have been the right thing here, i.e. keep the ownership with the Iterator, and just do a borrow. I get a similar issue if I get rid of ref
in the let changing the let to this:
let (k, v) = x; (&k, &v)
Then k
and v
don't live long enough. Does anyone have a recommendation for fixing this?
Since your
params
argument is created from aVec<(String, String)>
you can change your where clause towhere I: Iterator<Item=(&str, &str)>
and get the iterator by callingA simplified example:
You can't have an iterator that (safely) yields references to any internal or owned state; the
Iterator
trait is just not designed to allow it. These sorts of constructs are usually known as "streaming iterators", and they're something of a hole in the language/stdlib at the moment.Consider what happens to a
(String, String)
value as it flows through yourmap
call. Each tuple is returned fromI::next
, which causes ownership to pass into the closure you gave tomap
. Thus, when you useref
in the closure, you're taking a reference to variables which are local to the closure. You now construct a new tuple, return it and... because the closure owns theString
s (they're being stored ink
andv
), they are destroyed, thus invalidating the references you tried to return.The problem is that there is no way to avoid taking ownership of the
(String, String)
items.Now, that having been said, you can cheat here. All you need to do is guarantee that the
(String, String)
values continue to exist beyond each individual step in the iterator. Thus:This works because
Vec::iter
gives usIterator<Item=&(String, String)>
, from which we can borrow without taking ownership (which is retained byparams
).