2014-10-23 17 views

risposta

8

Su Rust 1.5.x, una soluzione di lavoro è:

fn main() {  
    let mut numbers = String::new(); 

    io::stdin().read_line(&mut numbers).ok().expect("read error"); 

    let numbers: Vec<i32> = numbers 
     .split_whitespace() 
     .map(|s| s.parse().unwrap()) 
     .collect(); 

    for num in numbers { 
     println!("{}", num); 
    } 
} 
12

aggiornato per Rust 1.x

si può fare qualcosa di simile:

Per prima cosa, prendiamo un blocco dello stdin che consente di lavorare con stdin come lettore bufferizzato (per impostazione predefinita, stdin in Rust è unbuffered; è necessario chiamare il metodo lock() per ottenere una versione bufferizzata di esso, ma questa versione bufferizzata è solo uno per tutti i thread nel programma, quindi l'accesso ad esso deve essere sincronizzato).

Successivamente, leggiamo la riga successiva (1); Sto usando l'iteratore lines() il cui metodo next() restituisce Option<io::Result<String>>, quindi per ottenere solo String è necessario unwrap() due volte.

Quindi lo dividiamo per spazi e tagliamo i pezzi risultanti da spazi bianchi extra (2), rimuoviamo i pezzi vuoti rimasti dopo il ritaglio (3), convertiamo le stringhe in i32 s (4) e raccogliamo il risultato in un vettore (5).

Abbiamo anche bisogno di importare std::io::BufRead tratto (a) per utilizzare il metodo lines().

Se si conosce in anticipo che il vostro ingresso non conterrà più di uno spazio tra i numeri, è possibile omettere il passo (3) e spostare trim() chiamata da (2) a (1):

let numbers: Vec<i32> = 
    reader.lock() 
      .lines().next().unwrap().unwrap() 
      .trim().split(' ') 
      .map(|s| s.parse().unwrap()) 
      .collect(); 

Aggiorna

ruggine, però, già fornisce un metodo per dividere una stringa in una sequenza di parole separati da spazi bianchi, chiamato split_whitespace():

let numbers: Vec<i32> = 
    reader.read_line().unwrap().as_slice() 
     .split_whitespace() 
     .map(|s| s.parse().unwrap()) 
     .collect() 

split_whitespace() è in realtà solo una combinazione di split() e filter(), proprio come nel mio esempio originale. Usa una funzione nell'argomento split() che controlla i diversi tipi di spazi bianchi, non solo i caratteri di spazio. È possibile trovare la sua fonte è here.

+0

Grazie Vladimir, hai salvato la giornata. Una nota a parte, wow, Rust è davvero intenso! –

+1

Esiste anche un modo per utilizzare le espressioni regolari per dividere per spazi vuoti arbitrari. Probabilmente darebbe il codice terser, ma richiede l'utilizzo di casse non standard (sebbene sia incluso nella distribuzione). L'esempio [qui] (http://doc.rust-lang.org/regex/enum.Regex.html#method.split) è quasi quello che vuoi. –

+4

Puoi anche usare ['.words()'] (http://doc.rust-lang.org/nightly/std/str/trait.UnicodeStrSlice.html#tymethod.words) (leggermente più generale dei semplici spazi , anche se). – huon

1

versione più sicura. Questo salta l'analisi fallita in modo che lo scartamento fallito non si faccia prendere dal panico. Utilizzare read_line per la lettura di una singola riga.

let mut buf = String::new(); 

// use read_line for reading single line 
std::io::stdin().read_to_string(&mut buf).expect(""); 

// this one skips failed parses so that failed unwrap doesn't panic 
let v: Vec<i32> = buf.split_whitespace().filter_map(|w| w.parse().ok()).collect(); 

Si può anche leggere Vettore di Vettori come questo.

let stdin = io::stdin(); 
let locked = stdin.lock(); 
let vv: Vec<Vec<i32>> = locked.lines() 
    .filter_map(
     |l| l.ok().map(
      |s| s.split_whitespace() 
       .filter_map(|word| word.parse().ok()) 
       .collect())) 
    .collect(); 

Sopra si lavora per gli ingressi come

2 424 -42 124 
42 242 23 22 241 
24 12 3 232 445 

poi si trasforma li in

[[2, 424, -42, 124], 
[42, 242, 23, 22, 241], 
[24, 12, 3, 232, 445]] 

filter_map accetta una chiusura che restituisce Option<T> e filtra tutti None s.

ok() gira Result<R,E> a Option<R> in modo che gli errori possano essere filtrati in questo caso.

Problemi correlati