我无法从(String, String)
的迭代器转换为(&str, &str)
的迭代器。我使用的是外部库,因此无法更改其签名,也不确定是否需要。基本上我有这个功能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) } ));
}
但是我得到了可怕的:error: 'x.0' does not live long enough
我认为let中的ref
关键字在这里应该是正确的,即保留所有权与迭代器,并且只是借用。如果我在let let to this:
ref
,我会遇到类似的问题
let (k, v) = x; (&k, &v)
然后k
和v
的活动时间不够长。有没有人建议解决这个问题?
答案 0 :(得分:6)
你不能拥有一个(安全地)产生对任何内部或拥有状态的引用的迭代器; Iterator
特征不是为了允许它而设计的。这些类型的构造通常被称为&#34;流式迭代器&#34;,它们目前在语言/ stdlib中是一个漏洞。
考虑(String, String)
值在map
调用时会发生什么情况。每个元组都从I::next
返回,这会导致所有权传递到您给map
的闭包中。因此,当您在闭包中使用ref
时,您将引用对闭包本地的变量。你现在构造一个新的元组,返回它并且......因为闭包拥有String
s(它们被存储在k
和v
中),它们被销毁了,从而使您尝试返回的引用无效。
问题在于无法以避免取得(String, String)
项的所有权。
现在,已经说过,你可以在这里作弊。您需要做的就是保证(String, String)
值继续存在于迭代器中的每个单独步骤之外。因此:
let params: Vec<_> = params.collect();
url.set_query_from_pairs(params.iter().map(|&(ref x, ref y)| (&x[..], &y[..])))
这是有效的,因为Vec::iter
为我们提供了Iterator<Item=&(String, String)>
,我们可以从中借用而不取得所有权(由params
保留)。
答案 1 :(得分:2)
由于您的params
参数是从Vec<(String, String)>
创建的,您可以将where子句更改为where I: Iterator<Item=(&str, &str)>
并通过调用
your_vector.iter().map(|(a, b)|, (&a[..], &b[..])))
简化示例:
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[..]));
}