简体   繁体   English

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

[英]What's the most efficient way to reuse an iterator in Rust?

I'd like to reuse an iterator I made, so as to avoid paying to recreate it from scratch. 我想重用我制作的迭代器,以避免付费从头开始重新创建它。 But iterators don't seem to be clone able and collect moves the iterator so I can't reuse it. 但是迭代器似乎不能clone并且collect会移动迭代器,所以我无法重用它。

Here's more or less the equivalent of what I'm trying to do. 这或多或少相当于我正在尝试做的事情。

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...
}

You should profile before you optimize something, otherwise you might end making things both slower and more complex than they need to. 你就应该剖析您优化前的东西,否则你可能最终使事情慢,要复杂得多,他们需要。

The iterators in your example 示例中的迭代器

let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );

are thin structures allocated on the stack. 是堆栈上分配的瘦结构。 Cloning them isn't going to be much cheaper than building them from scratch. 克隆它们并不比从头开始构建它们便宜得多。

Constructing an iterator with .chars().flat_map(|c| c.to_uppercase()) takes only a single nanosecond when I benchmark it. 使用.chars().flat_map(|c| c.to_uppercase())构造一个迭代器只需要一纳秒就可以进行基准测试

According to the same benchmark, wrapping iterator creation in a closure takes more time than simply building the iterator in-place. 根据相同的基准测试,在闭包中包装迭代器创建比简单地就地构建迭代器需要更多的时间。

Cloning a Vec iterator is not much faster than building it in-place, both are practically instant. 克隆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)

Iterators in general are Clone -able if all their "pieces" are Clone -able. 如果所有的“碎片”都是可Clone那么迭代器通常是Clone You have a couple of them in my_iter that are not: the anonymous closures (like the one in flat_map) and the ToUppercase struct returned by to_uppercase . 你在my_iter中有几个不是:匿名闭包(比如flat_map中的闭包)和to_uppercase返回的ToUppercase结构。

What you can do is: 你能做的是:

  1. rebuild the whole thing (as @ArtemGr suggests). 重建整个事物(如@ArtemGr建议)。 You could use a macro to avoid repetition. 您可以使用宏来避免重复。 A bit ugly but should work. 有点难看,但应该工作。
  2. collect my_iter into a Vec before populating my_struct (since you seem to collect it anyway in there): 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_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. create your own custom iterator. 创建自己的自定义迭代器。 Without your definitions of my_string (since you call unwrap_or on it I assume it's not a String ) and Tag it's hard to help you more concretely with this. 没有你对my_string的定义(因为你在它上面调用unwrap_or我认为它不是一个String )并且Tag它很难用这个来更具体地帮助你。

You may use closure to get identical iterators: 您可以使用闭包来获得相同的迭代器:

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

See also this Correct way to return an Iterator? 另请参阅这种返回迭代器的正确方法? question. 题。

Also you may clone iterator (see @Paolo Falabella answer about iterators cloneability): 你也可以克隆迭代器(参见@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<_>>());
}

Unfortunately I can't tell which way is more effective 不幸的是,我不知道哪种方式更有效

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM