我无法从Iterator转换(String, String)为Iterator (&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) } ));
}
Run Code Online (Sandbox Code Playgroud)
但我得到了可怕的: error: 'x.0' does not live long enough
我认为reflet中的关键字应该是正确的,即保持所有权与迭代器,并只是借用.我得到了一个类似的问题,如果我摆脱ref让let更改let to this:
let (k, v) = x; (&k, &v)
Run Code Online (Sandbox Code Playgroud)
然后k,v不要活得足够长.有没有人有建议解决这个问题?
你不能拥有一个(安全地)产生对任何内部或拥有状态的引用的迭代器; 这个Iterator特性并不是为了让它成为可能.这些类型的构造通常被称为"流式迭代器",而且它们目前在语言/ stdlib中是一个漏洞.
考虑(String, String)值在流经您的map呼叫时会发生什么.每个元组都会从中返回I::next,这会导致所有权传递到您给出的闭包中map.因此,当您ref在闭包中使用时,您将引用闭包本地的变量.你现在构造一个新元组,返回它并...因为闭包拥有Strings(它们存储在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[..])))
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为Vec::iter给了我们Iterator<Item=&(String, String)>,我们可以从中借用而不取得所有权(由其保留params).