我如何在 Rust 中处理切片范围?
How do I process a range in slices in Rust?
我知道在 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 的方法是什么?
如果需要可变性,请使用chunks
(or 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
可以创建新数组来填充值而不必担心所有权和 return 每次都创建一个新数组(检查 this_slice.object_id
)。
在 Rust 中,每次都分配一个新的向量是很不寻常的。此外,由于复杂的生命周期问题,您不能轻易 return 对迭代器持有的向量的引用。
一个与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);
}
}
收集到 vec 很容易扼杀你的表现。类似于问题中的方法非常好。
fn chunk_range(range: Range<usize>, chunk_size: usize) -> impl Iterator<Item=Range<usize>> {
range.clone().step_by(chunk_size).map(move |block_start| {
let block_end = (block_start + chunk_size).min(range.end);
block_start..block_end
})
}
我知道在 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 的方法是什么?
如果需要可变性,请使用chunks
(or 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
可以创建新数组来填充值而不必担心所有权和 return 每次都创建一个新数组(检查 this_slice.object_id
)。
在 Rust 中,每次都分配一个新的向量是很不寻常的。此外,由于复杂的生命周期问题,您不能轻易 return 对迭代器持有的向量的引用。
一个与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);
}
}
收集到 vec 很容易扼杀你的表现。类似于问题中的方法非常好。
fn chunk_range(range: Range<usize>, chunk_size: usize) -> impl Iterator<Item=Range<usize>> {
range.clone().step_by(chunk_size).map(move |block_start| {
let block_end = (block_start + chunk_size).min(range.end);
block_start..block_end
})
}