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

时间:2015-04-23 08:50:13

标签: rust lifetime

我无法从(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)

然后kv的活动时间不够长。有没有人建议解决这个问题?

2 个答案:

答案 0 :(得分:6)

你不能拥有一个(安全地)产生对任何内部或拥有状态的引用的迭代器; Iterator特征不是为了允许它而设计的。这些类型的构造通常被称为&#34;流式迭代器&#34;,它们目前在语言/ stdlib中是一个漏洞。

考虑(String, String)值在map调用时会发生什么情况。每个元组都从I::next返回,这会导致所有权传递到您给map的闭包中。因此,当您在闭包中使用ref时,您将引用对闭包本地的变量。你现在构造一个新的元组,返回它并且......因为闭包拥有String s(它们被存储在kv中),它们被销毁了,从而使您尝试返回的引用无效。

问题在于无法以避免取得(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[..]));
}