如何将 (String, String) 元组上的迭代器转换为 (&str, &str) 的迭代器?

How to convert an Iterator on a tuple of (String, String) to an Iterator of (&str, &str)?

我在从 (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 中删除 ref 将 let 更改为:

,我会遇到类似的问题
let (k, v) = x; (&k, &v)

kv活的不够长。有人有解决此问题的建议吗?

你不能有一个(安全地)产生对任何内部或拥有状态的引用的迭代器; Iterator 特性并不是为了允许它而设计的。这些类型的构造通常被称为 "streaming iterators",目前它们在 language/stdlib 中有点像一个洞。

考虑 (String, String) 值在通过您的 map 调用时会发生什么。每个元组都是从 I::next 编辑而来的 return,这会导致所有权传递到您给 map 的闭包中。因此,当您在闭包中使用 ref 时,您正在引用闭包 的局部变量 。你现在构建一个新的元组,return 它并且...因为闭包拥有 Strings(它们存储在 kv 中),它们是销毁,从而使您尝试 return.

的引用无效

问题是没有办法避免取得 (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 保留) .

由于您的 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[..]));
}