2014-09-27 6 views
7

sto imparando Rust, e ho scritto il seguente codice per leggere una serie di numeri interi da stdin:Utilizzando un `let` vincolante per aumentare il ciclo di vita del valore

use std::io; 
fn main() { 
    for line in io::stdin().lines() { 
     let xs:Vec<int> = line.unwrap().as_slice().trim().split(' ') 
       .map(|s|from_str::<int>(s).unwrap()).collect(); 
     println!("{}", xs); 
    } 
} 

Questo funzionava bene, però, ho sentito il let xs linea era un po 'lunga, quindi ho diviso in due:

fn main() { 
    for line in io::stdin().lines() { 
     let ss = line.unwrap().as_slice().trim().split(' '); 
     let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); 
     println!("{}", xs); 
    } 
} 

questo non ha funzionato! Ruggine ha risposto con il seguente errore:

hello.rs:4:12: 4:25 error: borrowed value does not live long enough 
hello.rs:4  let ss = line.unwrap().as_slice().trim().split(' '); 
         ^~~~~~~~~~~~~ 
hello.rs:3:34: 7:3 note: reference must be valid for the block at 3:33... 
hello.rs:3 for line in io::stdin().lines() { 
hello.rs:4  let ss = line.unwrap().as_slice().trim().split(' '); 
hello.rs:5  let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); 
hello.rs:6  println!("{}", xs); 
hello.rs:7 } 
hello.rs:4:3: 4:54 note: ...but borrowed value is only valid for the statement at 4:2; consider using a `let` binding to increase its lifetime 
hello.rs:4  let ss = line.unwrap().as_slice().trim().split(' '); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
error: aborting due to previous error 

Questo mi confonde. È line o ss che non vive abbastanza a lungo? E come posso usare un legame let per aumentare la loro durata? Pensavo di usare già un let?

Ho cercato sul Web soluzioni e ho letto il numero Lifetime guide, ma non riesco ancora a capirlo. Qualcuno può darmi un suggerimento?

risposta

9

Nella seconda versione, il tipo di ss è CharSplits<'a, char>. Il parametro lifetime nel tipo ci dice che l'oggetto contiene un riferimento. Affinché il compito sia valido, il riferimento deve puntare a un oggetto che esiste dopo quella dichiarazione. Tuttavia, unwrap() consuma line; in altre parole, sposta i dati della variante Ok dall'oggetto Result. Pertanto, il riferimento non punta all'interno dell'originale line, ma piuttosto su un oggetto temporaneo.

Nella prima versione, si consuma il temporaneo alla fine dell'espressione lunga, anche se la chiamata a map. Per risolvere il tuo seconda versione, è necessario associare il risultato di unwrap() per mantenere il valore di vivere abbastanza a lungo:

use std::io; 

fn main() { 
    for line in io::stdin().lines() { 
     let line = line.unwrap(); 
     let ss = line.as_slice().trim().split(' '); 
     let xs: Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); 
     println!("{}", xs); 
    } 
} 
+0

Giusto per essere sicuro di aver capito bene, 'CharSplits' fa riferimento al valore all'interno di' line'. Ma in realtà fa riferimento a una copia presa da "Ok", che viene buttata via non appena finisce la riga "Let's". Invece di mantenere tutti i valori vivi fino alla fine del blocco? –

+0

Sì. I valori temporanei sono validi solo per l'istruzione in cui si trova l'espressione che produce quel valore. –

+0

Non è uno spreco di memoria non puntare all'interno della 'linea'? –

3

Si tratta della chiamata unwrap(), sta ricevendo l'oggetto contenuto ma questo riferimento dovrebbe sopravvivere all'oggetto contenitore, che esce dall'ambito della riga successiva (non esiste alcun binding locale).

Se si desidera ottenere codice più pulito, un modo molto comune di scriverlo è:

use std::io; 

fn main() { 
    for line in io::stdin().lines() { 
     let xs:Vec<int> = 
      line 
      .unwrap() 
      .as_slice() 
      .trim() 
      .split(' ') 
      .map(
       |s|from_str::<int>(s).unwrap() 
      ) 
      .collect(); 
     println!("{}", xs); 
    } 
} 

In caso contrario, è possibile creare il legame al risultato "unwraped" e usarlo.

Spero che abbia aiutato.

+0

Quindi lei sta dicendo che il 'Line' è fuori del campo di applicazione del' lasciare xs' linea, ma non nella riga 'let ss', anche se sono nello stesso blocco? –

+1

È il risultato di 'line.unwrap()' che non rientra nell'ambito. – snf

+0

Grazie penso che sto iniziando a prenderlo. –