2015-07-12 15 views
7

Co powinienem zrobić, jeśli chcę przeprowadzić iterację z niestandardowym krokiem w stabilnej wersji Rust? Zasadniczo coś jak C/C++Jaki jest stabilny sposób na iterowanie w zakresie z niestandardowym krokiem?

for (int i = 0; i < n; i += 2) { 

} 

Ja już próbowałem przy użyciu range_step_inclusive i rozwiązania w How do I iterate over a range with a custom step?:

use std::iter::range_step_inclusive; 
for i in range_step_inclusive(0, n, 2) { 
    println!("i: {}", i); 
} 

Ale wydaje się, że nie jest ona dostępna w Rust 1.1:

error: unresolved import `std::iter::range_step_inclusive`. There is no `range_step_inclusive` in `std::iter` 

Jaka byłaby alternatywa? Prawdopodobnie idiomatyczny sposób tworzenia niestandardowych zakresów.

+1

Edytowałem twój tytuł, aby wyjaśnić, że szukasz rozwiązania, które ma zastosowanie do ** stabilnego ** Rdzy, w przeciwnym razie byłby to [być dupe] (http: // stackoverflow.com/q/27893223/155423). – Shepmaster

+0

Możliwy duplikat [Jak mogę wykonać iterację w zakresie z niestandardowym krokiem?] (Http://stackoverflow.com/questions/27893223/how-do-i-ateiter-over-a-range-w-ustom -step) – cambunctious

Odpowiedz

3

Jak Rust 1,1

Zawsze można napisać go w staromodny sposób:

fn main() { 
    let mut i = 0; 
    while i < 100 { 
     println!("i: {}", i); 
     i += 2;  
    } 
} 

które następnie mogą być pobieranej:

use std::ops::Add; 

fn step_by<T, F>(start: T, end_exclusive: T, step: T, mut body: F) 
    where T: Add<Output = T> + PartialOrd + Copy, 
      F: FnMut(T) 
{ 
    let mut i = start; 
    while i < end_exclusive { 
     body(i); 
     i = i + step;  
    } 
} 

fn main() { 
    step_by(0, 100, 2, |i| { 
     println!("i: {}", i); 
    }) 
} 

ciekawe historyczne marginesie Sądzę, że pierwotnie wszystkie pętle zostały wykonane z takimi zamknięciami, zanim iteratory stały się niezwykle rozpowszechnione.

+1

Miałem nadzieję na bardziej "eleganckie" i wbudowane rozwiązanie, ale wydaje mi się, że tak właśnie dzieje się z nowymi (ish) językami. Dzięki! – Sosdoc

+1

@Sosdoc krok po kroku jest bardzo oczekiwanym dodatkiem! To po prostu okazuje się być skomplikowane. Co robisz w przypadkach skrajnych, takich jak przekraczanie granic twojego typu w dowolnym kierunku? Lub radzenia sobie z krokami o zero? Zaskakujące są małe szczegóły, które są możliwe. Zauważ, że moje rozwiązanie nie ma nic, co mogłoby uniemożliwić ci niewłaściwe użycie. :-) – Shepmaster

+1

Wiem, byłam trochę zakłopotana, że ​​nie mogłam znaleźć czegoś, do czego byłam przyzwyczajona, odkąd błądziłam z C. – Sosdoc

5

Istnieje sposób korzystania let "przedefiniowanie":

for i in 0..((n + 1)/2) { 
    let i = i * 2; 
    // … 
} 

Albo użyć Iterator::map:

for i in (0..((n + 1)/2)).map(|i| i * 2) { 
    // … 
} 
+2

Myślę, że to skróci ci ostatni indeks, jeśli n jest nieparzyste z powodu zaokrąglenia. Jeśli n = 5, (n/2) = 2, będziesz miał wartość i w 0..2, a iterator nie jest włączony. Zapewni to tylko i = 0, i = 2 w wewnętrznej pętli, będziesz brakować i = 4, jak zapewniłaby pętla w stylu C. – coconaut

+1

W takim przypadku użyj '(n + 1)/2'. – Hauleth

+0

Brzmi nieźle! – coconaut

3

myślę będę trzymać do pętli while. Ale jeśli naprawdę chcesz się metodę opartą iterator można spróbować tego

fn main(){ 
    let (start, step, end) = (1, 2, 20); 
    for i in (0..).map(|x| start+step*x) 
        .take_while(|&x| x<end){ 
     println!("{:?}", i); 
    } 
} 
3

Użyj crate num

Cargo.toml:

[dependencies.num] 
version = "0.1.25" 
default-features = false 

ponieważ trzeba tylko podstawy skrzyni, użyj default-features = false.

Rust:

extern crate num; 

use num::range_step; 

for i in range_step(0, 10, 2) { 
    /* */ 
} 

range_step jest nazwą rodzajową nad typów całkowitych Rust.

-1

Można użyć funkcji iterator_step_by.

Oto przykład dwóch wątków uruchomiony jeden z nich drukując numery nieparzyste i inne nawet te:

#![feature(iterator_step_by)] 
extern crate thebook; 

use std::thread; 
use std::time::Duration; 
fn main() { 
    let handle = thread::spawn(|| { 
     for i in (1..1000).step_by(2) { 
      println!("{}", i); 
     } 
    }); 
    for i in (2..1000).step_by(2) { 
     println!("{}", i); 
    } 
    handle.join(); 
} 

bez tej funkcji, można również użyć filtra w zakresie:

use std::thread; 
use std::time::Duration; 
fn main() { 
    let handle = thread::spawn(|| { 
     for i in (1..1000).filter(|x| x % 2 != 0) { 
      println!("{}", i); 
     } 
    }); 
    for i in (2..1000).filter(|x| x % 2 == 0) { 
     println!("{}", i); 
    } 
    handle.join(); 
} 
+0

Funkcje są wyraźnie ** niedozwolone ** w stabilnej Rdze, o to chodzi. – Shepmaster

+0

Wystarczająco fair. Właśnie dodałem podejście oparte na filtrach. – qed