2015-04-21 4 views
10

Sto riscontrando dei problemi nel tentativo di comprendere perché non è possibile restituire un valore &str generato da un String (qualità, quando sarà pronto il as_str?) E sto facendo qualcosa di sbagliato. Ho questa idea perché nulla di ciò che faccio fa vivere il valore abbastanza a lungo da poterlo utilizzare.Perché non posso restituire un valore & str generato da una stringa?

Sto cercando di implementare error::Error per una struct personalizzato:

impl error::Error for LexicalError { 
    fn description(&self) -> &str { 
     let s = format!("{}", self); 

     // s doesn't live long enough to do this, I've tried 
     // cloning s and using that, but still the clone doesn't 
     // live long enough. 
     s.trim() 
    } 

    fn cause(&self) -> Option<&error::Error> { 
     None 
    } 
} 

(per il frammento di completo, qui è la playpen)

Non riesco a capire come restituire un & str da description, vorrei riutilizzare la logica Display, a meno che, ovviamente, non stia completamente fraintendendo cosa dovrebbe restituire description (forse la breve descrizione del problema). O ottengo lo stesso problema con il ritorno di format!(...) che è una variabile che non riesco a vivere abbastanza a lungo da essere utile a me.

+3

'description' dovrebbe essere una descrizione dell'errore che non entra nei dettagli; 'fmt :: Display' dovrebbe essere lì per aumentarlo con dettagli come desiderato. –

+0

@ChrisMorgan Vengo dal Go come linguaggio più recente con cui ho giocato e ho erroneamente pensato che il metodo description fosse simile al metodo Go's Error. Grazie per le informazioni! –

risposta

12

In primo luogo, diamo un'occhiata a ciò che la vita è effettivamente prevista. C'è una vita implicita nella firma del description:

fn description(&self) -> &str 
// Can be rewritten as 
fn description<'a>(&'a self) -> &'a str 

Il puntatore restituito deve essere valido per almeno finché self. Considerare ora s. Conterrà un String, una stringa di proprietà e uscirà dall'ambito alla fine della funzione. Non sarebbe valido restituire &s, perché s non c'è più quando la funzione ritorna. trim restituisce una sezione stringa che prende in prestito s, ma la sezione è di nuovo valida solo finché lo è s.

È necessario restituire una sezione di stringa che sopravvive alla chiamata al metodo, in modo da escludere qualsiasi elemento presente nello stack. Se sei libero di scegliere il tipo di reso, una soluzione sarebbe spostare la stringa fuori dalla funzione. Per quello sarebbe richiesta una stringa di proprietà, e quindi il tipo restituito sarebbe String, non &str. Sfortunatamente, non sei libero di scegliere il tipo di reso qui.

Per tornare una fetta stringa che sopravvive della chiamata al metodo, vedo due opzioni:

  1. utilizzare una fetta &'static stringa. Questo sicuramente sopravviverà alla chiamata, ma richiede che la stringa sia nota al momento della compilazione. I valori letterali stringa hanno tipo &'static str. Questa è un'opzione adatta se la descrizione non contiene dati dinamici.

  2. Conservare una stringa di proprietà in LexicalError stesso. Ciò garantisce che sia possibile restituire un puntatore ad esso valido per l'intera durata di self. È possibile aggiungere un campo desc: String a LexicalError ed eseguire la formattazione quando si crea l'errore. Quindi il metodo verrebbe implementato come

    fn description(&self) -> &str { 
        &self.desc 
    } 
    

    per il riutilizzo, è possibile effettuare Display scrivere la stessa stringa.

Secondo la documentation of Error, Display può essere utilizzato per fornire ulteriori dettagli.Se desideri includere dati dinamici nell'errore, allora Display è un ottimo posto per formattarlo, ma puoi ometterlo per description. Ciò consentirebbe di utilizzare il primo approccio.

+0

Penso che la seconda opzione mi soddisfi meglio. Il che mi porta a porre una domanda semi-correlata - sono 'String' e' & str' intercambiabili? Oppure, suppongo 'String' e' str' in questo caso, altrimenti sarebbe opportuno restituire un '& str' preso in prestito. Ho una scarsa comprensione della differenza esatta tra 'String' e' & str' oltre a quando si verificano (ad esempio, conosco il tipo di stringhe letterali e quando si costruiscono stringhe più complesse di una semplice formattazione io uso 'String') e quando per (leggermente) scegliere tra di loro. –

+0

Non sono intercambiabili. Un 'String' possiede i suoi byte UTF-8, mentre un' & str' punta semplicemente ai byte UTF-8 presi in prestito da qualche parte. 'String' e' & str' sono analoghi a 'Vec ' e '& [T]'. Puoi prendere in prestito un 'String' per ottenere un' & str'. In tal caso, la porzione presa in prestito non può sopravvivere al possesso di 'String'. C'è [un capitolo sulle stringhe nel libro] (http://doc.rust-lang.org/1.0.0-beta.2/book/strings.html), che può essere utile. – Ruud

+0

Ho letto il libro, quello che hai detto ha più senso di quello che ricordo. Forse non avevo avuto abbastanza comprensione della lingua per cogliere quella sezione. Grazie per le informazioni, è stato di grande aiuto. –