什么是在Rust中重用迭代器的最有效方法?

时间:2016-02-15 05:44:35

标签: iterator rust move-semantics

我想重用我制作的迭代器,以避免付费从头开始重新创建它。但是迭代器似乎没有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...
}

3 个答案:

答案 0 :(得分:8)

在优化某些内容之前,您应该进行配置,否则您可能会使 的内容变得更慢,更复杂。

示例中的迭代器

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)

答案 1 :(得分:5)

一般的迭代器是Clone - 如果他们所有的"片段都是有效的。是Clone - 能够。你在my_iter中有几个不是:匿名闭包(如flat_map中的闭包)和to_uppercase返回的ToUppercase结构。

你能做的是:

  1. 重建整个事物(正如@ArtemGr建议的那样)。您可以使用宏来避免重复。有点难看,但应该工作。
  2. 在填充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();
  3. 创建自己的自定义迭代器。没有您对my_string的定义(因为您在其上致电unwrap_or我认为它不是String)而Tag很难帮助您更具体地说。

答案 2 :(得分:4)

您可以使用闭包来获得相同的迭代器:

#[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<_>>());
}

不幸的是我不知道哪种方式更有效