2015-09-06 2 views
5

Sto cercando di capire come scrivere il corretto codice Rust, ma penso di poter sopravvalutare il potere della capacità del compilatore di capire la durata dei miei oggetti. Questo è il codice come mi aspettavo di lavorare:Come restituire un percorso & da una funzione?

use std::path::Path; 
use std::env; 
use rusqlite::SqliteConnection; 

struct SomeDatabase { 
    conn: SqliteConnection, 
} 

impl SomeDatabase { 
    fn getPath() -> &Path { 
     let path = env::home_dir().unwrap(); 
     path.push("foo.sqlite3"); 
     path.as_path() 
    } 

    fn open() -> SomeDatabase { 
     let path = SomeDatabase::getPath() 
     SomeDatabase { conn: SqliteConnection::open(path).unwrap() } 
    } 
} 

fn main() { 
    let db = SomeDatabase::open(); 
} 

Quando provo a compilare questo, ottengo un errore di un identificatore di vita mancante su &Path. So che se questo ha preso un parametro di riferimento dal chiamante, ci vorrebbe la stessa durata di quel riferimento. Qui però quello che mi aspettavo è che la vita sarebbe stata assegnata alla variabile a cui sto assegnando il risultato.

So che le vite possono essere aggiunte in modo esplicito, ma non so come applicarle in questo caso. Il compilatore suggerisce di provare la durata di 'static, ma questo non ha senso qui, per quanto ne so, perché l'origine del valore di ritorno di questa funzione non è statica.

Ora, solo per cercare di vedere cosa è successo se ho provato a compilare il resto del codice, ho cambiato il tipo di ritorno &Path-PathBuf e chiamato as_path() in open(). Questo ha causato il compilatore di uscita questi errori:

src\main.rs:22:30: 22:52 error: the trait `core::marker::Sized` is not implemented for the type `[u8]` [E0277] 
src\main.rs:22   SomeDatabase { conn: SqliteConnection::open(path).unwrap() } 
              ^~~~~~~~~~~~~~~~~~~~~~ 
src\main.rs:22:30: 22:52 note: `[u8]` does not have a constant size known at compile-time 
src\main.rs:22   SomeDatabase { conn: SqliteConnection::open(path).unwrap() } 
              ^~~~~~~~~~~~~~~~~~~~~~ 

SqliteConnection::open() restituisce un Result<SqliteConnection, SqliteError> e l'unico campo all'interno SqliteConnection è un RefCell, quindi non capire dove questo errore su un array di byte proviene.

Quindi, perché le cose non funzionano come mi aspetto e quale è il modo più arrugginito per scrivere questo codice?

risposta

7

Nel primo caso, si sta creando un valore e quindi si tenta di restituire un riferimento ad esso. Ma dal momento che non stai memorizzando quel valore da nessuna parte, esso viene distrutto al termine della funzione. Se fosse permesso, sarebbe un bug da utilizzare dopo l'uso.

Il motivo che ha suggerito la restituzione di un &'static Path è perché la funzione non è parametrizzata su qualsiasi vite, quindi l'unico corso della vita si può essere sicuri sopravvive tutto ciò che vuole utilizzare il valore di ritorno sarebbe 'static.

È corretto che è necessario restituire uno PathBuf direttamente anziché &Path.

Non sono del tutto sicuro del motivo per cui si ottengono gli errori di dimensione [u8].

Non è necessario chiamare "as_path()". SqliteConnection::open assume un valore che implementa AsRef<Path> (AsRef è una specie di tipo Into) e PathBuf implementa tale tratto.

+0

Mi rendo conto che nel primo caso sto restituendo un riferimento a qualcosa creato all'interno della funzione, ma se faccio getPath() una funzione membro di SomeDatabase, il compilatore è abbastanza intelligente da contenere il percorso & fino all'istanza di SomeDatabase va fuori dal campo di applicazione. Sto chiedendo se c'è un modo per dire al compilatore che la durata del riferimento appartiene alla funzione che sta chiamando getPath() (nel caso in cui getPath() sia una funzione associata). Il codice di durata dovrebbe essere fino a quando la variabile che contiene il riferimento non rientra nello scope in open(). –

+0

Devo anche aggiungere che se rimango as_path(), ottengo un errore di tipo non corrispondente: "previsto" & _ ", trovato" std :: path :: PathBuf "(previsto e -ptr, found struct" std :: path :: PathBuf ') –

+1

@AustinWagner La variabile 'path' è definita nel corpo del metodo' getPath() ', la sua durata termina alla fine dell'ambito di questo corpo di funzione, a meno che non la si restituisca. per evitare questa regola Nel tuo caso non c'è alternativa alla restituzione della funzione 'PathBuf' per la funzione' getPath() ' – Levans