2015-07-12 8 views
7

Come devo andare se voglio ripetere con un passaggio personalizzato in Rust stabile? In sostanza qualcosa come il C/C++Qual è un modo stabile per iterare su un intervallo con passaggio personalizzato?

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

} 

Ho già provato con range_step_inclusive e le soluzioni in 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); 
} 

ma sembra come se non è disponibile in Rust 1.1:

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

Quale sarebbe un'alternativa? Forse il modo idiomatico per creare intervalli personalizzati.

+1

Ho modificato il titolo per chiarire che si sta cercando una soluzione valida per ** stable ** Rust, altrimenti ciò significherebbe [essere un duplicato] (http: // StackOverflow.com/q/27893223/155.423). – Shepmaster

+0

Possibile duplicato di [Come si esegue l'iterazione su un intervallo con un passaggio personalizzato?] (Http://stackoverflow.com/questions/27893223/how-do-i-iterate-over-a-range-with-a-custom -step) – cambunctious

risposta

3

Come di Rust 1.1

Si può sempre scrivere fuori la vecchia maniera:

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

che possono poi essere astrarre:

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

Interessante nota a margine storica , Credo che in origine tutto il ciclo fosse fatto con chiusure come questa, prima che gli iteratori diventassero estremamente diffusi.

+1

Speravo in una soluzione più "elegante" e built-in, ma immagino sia quello che succede con le nuove lingue (ish). Grazie! – Sosdoc

+1

@Sosdoc fare un passo con un incremento è un'aggiunta molto attesa! Si rivela essere complicato. Che cosa fai per casi limite come superare i limiti del tuo tipo in entrambe le direzioni? O gestire lo stepping di zero? È sorprendente i piccoli dettagli che sono possibili. Nota che la mia soluzione non ha nulla che ti impedisca di usarlo male. :-) – Shepmaster

+1

Lo so, ero solo un po 'perplesso di non riuscire a trovare qualcosa a cui ero abituato da quando stavo armeggiando con C. – Sosdoc

5

Non c'è modo usando let "ridefinizione":

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

Oppure utilizzare Iterator::map:

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

Penso che questo ti farà diventare l'ultimo indice se n è dispari a causa dell'arrotondamento. Se n = 5, (n/2) = 2, quindi avrai i in 0..2 e l'iteratore non è inclusivo. Questo fornirà solo i = 0, i = 2 nel ciclo interno, ti mancheranno i = 4 come il ciclo in stile C avrebbe fornito. – coconaut

+1

In questo caso usa '(n + 1)/2'. – Hauleth

+0

Mi sembra buono! – coconaut

3

Penso che continuerò ad un ciclo while. Ma se si vuole veramente un metodo basato iteratore si potrebbe provare questo

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

Utilizzare il crate num

Cargo.toml:

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

Dal momento che è necessario solo nozioni di base della cassa, utilizzare default-features = false.

Rust:

extern crate num; 

use num::range_step; 

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

range_step è generico su tipi interi di ruggine.

-1

È possibile utilizzare la funzione iterator_step_by.

Ecco un esempio di due thread in esecuzione, uno di loro stampare i numeri dispari e gli altri anche:

#![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(); 
} 

Senza questa funzionalità, è possibile utilizzare anche un filtro sulla gamma:

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

Le funzioni sono espressamente ** non consentite ** in Rust stabile, di cui tratta questa domanda. – Shepmaster

+0

Abbastanza giusto. Ho appena aggiunto un approccio basato su filtri. – qed

Problemi correlati