【问题标题】:What's the most efficient way to reuse an iterator in Rust?在 Rust 中重用迭代器的最有效方法是什么?
【发布时间】:2016-05-25 22:37:32
【问题描述】:

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

【问题讨论】:

    标签: iterator rust move-semantics


    【解决方案1】:

    您应该在优化某些东西之前进行分析,否则您最终可能会使事情变得比他们需要的更慢和更复杂。

    示例中的迭代器

    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)
    

    【讨论】:

      【解决方案2】:

      如果迭代器的所有“部分”都是Clone-able,则迭代器通常是Clone-able。 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,很难更具体地帮助您。

      【讨论】:

      【解决方案3】:

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

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

      很遗憾,我不知道哪种方法更有效

      【讨论】:

        猜你喜欢
        • 2017-11-21
        • 2019-08-31
        • 1970-01-01
        • 2020-07-18
        • 2023-01-11
        • 2012-11-14
        • 1970-01-01
        • 1970-01-01
        • 2017-12-09
        相关资源
        最近更新 更多