如何在Rust中处理切片范围?

时间:2016-05-04 16:50:37

标签: vector rust slice

我理解在Rust中迭代的首选方法是通过for var in (range)语法,但有时候我想一次处理该范围内的多个元素。

从Ruby的角度来看,我试图在Rust中找到一种做(1..100).each_slice(5) do |this_slice|的方法。

我正在尝试像

这样的事情
for mut segment_start in (segment_size..max_val).step_by(segment_size) {
    let this_segment = segment_start..(segment_start + segment_size).iter().take(segment_size);
}

但我不断收到错误,表明我正在咆哮错误的 type 树。这些文档也没有帮助 - 它们只是不包含这个用例。

Rust的做法是什么?

1 个答案:

答案 0 :(得分:9)

如果您需要可变性,请使用chunks(或chunks_mut):

fn main() {
    let things = [5, 4, 3, 2, 1];

    for slice in things.chunks(2) {
        println!("{:?}", slice);
    }
}

输出:

[5, 4]
[3, 2]
[1]

最简单将此方法与Range相结合的方法是首先将范围收集到Vec(取消引用切片):

fn main() {
    let things: Vec<_> = (1..100).collect();

    for slice in things.chunks(5) {
        println!("{:?}", slice);
    }
}

纯粹迭代器的另一个解决方案是使用Itertools::chunks_lazy

extern crate itertools;

use itertools::Itertools;

fn main() {
    for chunk in &(1..100).chunks_lazy(5) {
        for val in chunk {
            print!("{}, ", val);
        }
        println!("");
    }
}

这表明类似的解决方案只需要标准库:

fn main() {
    let mut range = (1..100).peekable();

    while range.peek().is_some() {
        for value in range.by_ref().take(5) {
            print!("{}, ", value);
        }
        println!("");
    }
}

一个诀窍是Ruby和Rust在这里有不同的处理方式,主要集中在效率上。

在Ruby Enumerable中可以创建新数组来填充值而不必担心所有权并且每次都返回一个新数组(使用this_slice.object_id检查)。

在Rust中,每次分配一个新的向量都是非常不寻常的。此外,由于复杂的生命周期问题,您无法轻松返回对迭代器所持有的向量的引用。

与Ruby非常相似的解决方案是:

fn main() {
    let mut range = (1..100).peekable();

    while range.peek().is_some() {
        let chunk: Vec<_> = range.by_ref().take(5).collect();

        println!("{:?}", chunk);
    }
}

哪个可以包含在隐藏详细信息的新迭代器中:

use std::iter::Peekable;

struct InefficientChunks<I>
    where I: Iterator
{
    iter: Peekable<I>,
    size: usize,
}

impl<I> Iterator for InefficientChunks<I>
    where I: Iterator
{
    type Item = Vec<I::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.iter.peek().is_some() {
            Some(self.iter.by_ref().take(self.size).collect())
        } else {
            None
        }
    }
}

trait Awesome: Iterator + Sized {
    fn inefficient_chunks(self, size: usize) -> InefficientChunks<Self> {
        InefficientChunks {
            iter: self.peekable(),
            size: size,
        }
    }
}

impl<I> Awesome for I where I: Iterator {}

fn main() {
    for chunk in (1..100).inefficient_chunks(5) {
        println!("{:?}", chunk);
    }
}