如何将 (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)
那k
和v
活的不够长。有人有解决此问题的建议吗?
你不能有一个(安全地)产生对任何内部或拥有状态的引用的迭代器; Iterator
特性并不是为了允许它而设计的。这些类型的构造通常被称为 "streaming iterators",目前它们在 language/stdlib 中有点像一个洞。
考虑 (String, String)
值在通过您的 map
调用时会发生什么。每个元组都是从 I::next
编辑而来的 return,这会导致所有权传递到您给 map
的闭包中。因此,当您在闭包中使用 ref
时,您正在引用闭包 的局部变量 。你现在构建一个新的元组,return 它并且...因为闭包拥有 String
s(它们存储在 k
和 v
中),它们是销毁,从而使您尝试 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[..]));
}
我在从 (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)
那k
和v
活的不够长。有人有解决此问题的建议吗?
你不能有一个(安全地)产生对任何内部或拥有状态的引用的迭代器; Iterator
特性并不是为了允许它而设计的。这些类型的构造通常被称为 "streaming iterators",目前它们在 language/stdlib 中有点像一个洞。
考虑 (String, String)
值在通过您的 map
调用时会发生什么。每个元组都是从 I::next
编辑而来的 return,这会导致所有权传递到您给 map
的闭包中。因此,当您在闭包中使用 ref
时,您正在引用闭包 的局部变量 。你现在构建一个新的元组,return 它并且...因为闭包拥有 String
s(它们存储在 k
和 v
中),它们是销毁,从而使您尝试 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[..]));
}