如何在 Rust 中处理切片范围? [英] How do I process a range in slices in Rust?

查看:66
本文介绍了如何在 Rust 中处理切片范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I understand that the preferred way to iterate in Rust is through the for var in (range) syntax, but sometimes I'd like to work on more than one of the elements in that range at a time.

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

From a Ruby perspective, I'm trying to find a way of doing (1..100).each_slice(5) do |this_slice| in Rust.

我正在尝试类似的事情

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 树.文档也没有帮助 - 它们只是不包含此用例.

but I keep getting errors that suggest I'm barking up the wrong type tree. The docs aren't helpful either--they just don't contain this use case.

Rust 有什么方法可以做到这一点?

What's the Rust way to do this?

推荐答案

使用 (或 chunks_mut 如果你需要可变性):

Use chunks (or chunks_mut if you need mutability):

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

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

输出:

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

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

The easiest way to combine this with a Range would be to collect the range to a Vec first (which dereferences to a slice):

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

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

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

Another solution that is pure-iterator would be to use 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!("");
    }
}

这提出了一个类似的解决方案,只需要标准库:

Which suggests a similar solution that only requires the standard library:

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 在这里有不同的处理方式,主要集中在效率上.

One trick is that Ruby and Rust have different handling here, mostly centered around efficiency.

在 Ruby 中,Enumerable 可以创建新数组来填充值,而无需担心所有权并每次返回一个新数组(检查 this_slice.object_id).

In Ruby Enumerable can create new arrays to stuff values in without worrying about ownership and return a new array each time (check with this_slice.object_id).

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

In Rust, allocating a new vector each time would be pretty unusual. Additionally, you can't easily return a reference to a vector that the iterator holds due to complicated lifetime concerns.

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

A solution that's very similar to Ruby's is:

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

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

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

可以包含在一个隐藏细节的新迭代器中:

Which could be wrapped up in a new iterator that hides the details:

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

这篇关于如何在 Rust 中处理切片范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆