在 Rust 中重用迭代器的最有效方法是什么?
What's the most efficient way to reuse an iterator in Rust?
我想重复使用我制作的迭代器,以避免从头开始重新创建它。但是迭代器似乎无法 clone
并且 collect
移动了迭代器所以我不能重用它。
这大致相当于我正在尝试做的事情。
let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );
let my_struct = {
one: my_iter.collect(),
two: my_iter.map(|c|{(c,Vec::new())}).collect(),
three: my_iter.filter_map(|c|if c.predicate(){Some(c)}else{None}).collect(),
four: my_iter.map(|c|{(c,1.0/my_float)}).collect(),
five: my_iter.map(|c|(c,arg_time.unwrap_or(time::now()))).collect(),
//etc...
}
您可以使用闭包来获得相同的迭代器:
#[derive(Debug)]
struct MyStruct{
one:Vec<char>,
two:Vec<char>,
three:String
}
fn main() {
let my_string:String = "ABCD1234absd".into();
let my_iter = || my_string.chars();
let my_struct = MyStruct{
one: my_iter().collect(),
two: my_iter().filter(|x| x.is_numeric()).collect(),
three: my_iter().filter(|x| x.is_lowercase()).collect()
};
println!("{:?}", my_struct);
}
另请参阅此 Correct way to return an Iterator? 问题。
您也可以克隆迭代器(请参阅@Paolo Falabella 关于迭代器可克隆性的回答):
fn main() {
let v = vec![1,2,3,4,5,6,7,8,9];
let mut i = v.iter().skip(2);
let mut j = i.clone();
println!("{:?}", i.take(3).collect::<Vec<_>>());
println!("{:?}", j.filter(|&x| x%2==0).collect::<Vec<_>>());
}
遗憾的是我不知道哪种方式更有效
您应该在优化某些东西之前进行概要分析,否则您最终可能会使事情 变得比他们需要的更慢和更复杂。
您示例中的迭代器
let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );
是在堆栈上分配的精简结构。克隆它们并不比从头构建它们便宜多少。
用 .chars().flat_map(|c| c.to_uppercase())
构建一个迭代器只需要一纳秒,而我 benchmark 它。
根据相同的基准,将迭代器创建包装在闭包中比简单地就地构建迭代器需要更多时间。
克隆 Vec
迭代器并不比就地构建迭代器快多少,两者几乎都是即时的。
test construction_only ... bench: 1 ns/iter (+/- 0)
test inplace_construction ... bench: 249 ns/iter (+/- 20)
test closure ... bench: 282 ns/iter (+/- 18)
test vec_inplace_iter ... bench: 0 ns/iter (+/- 0)
test vec_clone_iter ... bench: 0 ns/iter (+/- 0)
如果迭代器的所有 "pieces" 都是 Clone
-able,那么迭代器一般都是 Clone
-able 的。 my_iter
中有几个不是:匿名闭包(如 flat_map 中的闭包)和 to_uppercase
.[=22= 返回的 ToUppercase 结构]
您可以做的是:
- 重建整个东西(正如@ArtemGr 建议的那样)。您可以使用宏来避免重复。有点难看,但应该可以。
- 在填充 my_struct 之前将
my_iter
收集到 Vec
中(因为您似乎无论如何都将其收集在那里):let my_iter: Vec<char> = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() ).collect();
- 创建您自己的自定义迭代器。没有你对
my_string
的定义(因为你在上面调用了 unwrap_or
我认为它不是 String
)和 Tag
很难更具体地帮助你。
我想重复使用我制作的迭代器,以避免从头开始重新创建它。但是迭代器似乎无法 clone
并且 collect
移动了迭代器所以我不能重用它。
这大致相当于我正在尝试做的事情。
let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );
let my_struct = {
one: my_iter.collect(),
two: my_iter.map(|c|{(c,Vec::new())}).collect(),
three: my_iter.filter_map(|c|if c.predicate(){Some(c)}else{None}).collect(),
four: my_iter.map(|c|{(c,1.0/my_float)}).collect(),
five: my_iter.map(|c|(c,arg_time.unwrap_or(time::now()))).collect(),
//etc...
}
您可以使用闭包来获得相同的迭代器:
#[derive(Debug)]
struct MyStruct{
one:Vec<char>,
two:Vec<char>,
three:String
}
fn main() {
let my_string:String = "ABCD1234absd".into();
let my_iter = || my_string.chars();
let my_struct = MyStruct{
one: my_iter().collect(),
two: my_iter().filter(|x| x.is_numeric()).collect(),
three: my_iter().filter(|x| x.is_lowercase()).collect()
};
println!("{:?}", my_struct);
}
另请参阅此 Correct way to return an Iterator? 问题。
您也可以克隆迭代器(请参阅@Paolo Falabella 关于迭代器可克隆性的回答):
fn main() {
let v = vec![1,2,3,4,5,6,7,8,9];
let mut i = v.iter().skip(2);
let mut j = i.clone();
println!("{:?}", i.take(3).collect::<Vec<_>>());
println!("{:?}", j.filter(|&x| x%2==0).collect::<Vec<_>>());
}
遗憾的是我不知道哪种方式更有效
您应该在优化某些东西之前进行概要分析,否则您最终可能会使事情 变得比他们需要的更慢和更复杂。
您示例中的迭代器
let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );
是在堆栈上分配的精简结构。克隆它们并不比从头构建它们便宜多少。
用 .chars().flat_map(|c| c.to_uppercase())
构建一个迭代器只需要一纳秒,而我 benchmark 它。
根据相同的基准,将迭代器创建包装在闭包中比简单地就地构建迭代器需要更多时间。
克隆 Vec
迭代器并不比就地构建迭代器快多少,两者几乎都是即时的。
test construction_only ... bench: 1 ns/iter (+/- 0)
test inplace_construction ... bench: 249 ns/iter (+/- 20)
test closure ... bench: 282 ns/iter (+/- 18)
test vec_inplace_iter ... bench: 0 ns/iter (+/- 0)
test vec_clone_iter ... bench: 0 ns/iter (+/- 0)
如果迭代器的所有 "pieces" 都是 Clone
-able,那么迭代器一般都是 Clone
-able 的。 my_iter
中有几个不是:匿名闭包(如 flat_map 中的闭包)和 to_uppercase
.[=22= 返回的 ToUppercase 结构]
您可以做的是:
- 重建整个东西(正如@ArtemGr 建议的那样)。您可以使用宏来避免重复。有点难看,但应该可以。
- 在填充 my_struct 之前将
my_iter
收集到Vec
中(因为您似乎无论如何都将其收集在那里):let my_iter: Vec<char> = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() ).collect();
- 创建您自己的自定义迭代器。没有你对
my_string
的定义(因为你在上面调用了unwrap_or
我认为它不是String
)和Tag
很难更具体地帮助你。