2016-05-04 31 views
4

我的理解是,在Rust中迭代的首選方法是通過for var in (range)語法,但有時我想一次處理該範圍中的多個元素。如何在Rust中處理切片範圍?

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

,但我不斷收到暗示我叫錯樹錯誤。文檔也沒有幫助 - 他們只是不包含這個用例。

什麼是鏽的方式來做到這一點?

回答

7

使用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和鏽病在這裏有不同的處理,主要集中在效率。

在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); 
    } 
} 
+1

範圍沒有大塊,在至少不在stable中:'error:找不到名爲'chunks'的類型爲'core :: ops :: Range '的當前作用域' –

+1

@TrevorAlexander我道歉;我讀得有點太快了!我添加了一些替代品。您可能想要向您的問題添加您的目標。根據我的經驗,我很少需要一堆數字。有可能有更好的整體方法。 – Shepmaster