2014-07-02 17 views
9

Considerare questa funzione che dovrebbe restituire l'estensione del file di un dato Path.Perché la variabile non vive abbastanza a lungo?

pub fn get_extension<'a>(path: &'a Path) -> Option<&'a str> { 
    let path_str = path.as_str().unwrap(); 
    let ext_pos = regex!(".[a-z0-9]+$").find(path_str); 

    match ext_pos { 
     Some((start, _)) => { 
      return Some(path_str.as_slice().slice_from(start)) 
     }, 
     None => return None 
    } 
} 

Il messaggio di errore è la seguente:

`path_str` does not live long enough 

enter image description here

messaggio L'errore è abbastanza chiaro ed è un peccato che non si può lavorare per conto mio. Lo capisco in teoria ma ci sono ancora un paio di cose sfocate per me.

Capisco che il compilatore vuole dirmi che path_str non vive abbastanza a lungo da essere valido come il valore restituito con è contrassegnato con la durata 'a.

Ma questo è dove si ferma per me:

  • Capisco che il riferimento al path (il parametro di ingresso) devono la vita esattamente fino a quando il riferimento al str che è avvolto nel Option (il parametro di uscita)

  • poiché restituiamo Some(path_str.as_slice().slice_from(start)) presumo che in pratica ciò significa che path_str ha bisogno di vivere fino a path.

Quello che non capisco è il motivo per cui esattamente fa path_str non vive abbastanza a lungo e come potrei risolvere questo problema? Cosa lo fa morire presto?

UPDATE

Come sottolineato nei commenti e anche su IRC rimozione del superfluo as_slice() rende il codice di compilazione. Qualcuno sa perchè è così? È stato anche sottolineato che esiste uno method per ottenere direttamente l'estensione. Ma sì, in realtà sono più interessato ad apprendere la storia dietro il problema.

+1

Path_str è già una sezione in modo da poterla rimuovere as_slice e funzionerà. Questo è probabilmente un bug. – Arjan

+0

Grazie. Questo ha fatto il trucco. Aggiorno la domanda di conseguenza. – Christoph

risposta

12

Questo non è un bug. Il "problema" qui è la definizione di as_slice. Prende un riferimento ai suoi argomenti e restituisce uno &str con la stessa durata del riferimento , non può introspettarsi nelle durate interne di qualsiasi tipo venga chiamato. Vale a dire, path_str.as_slice() restituisce un &str che dura fino a path_str, non fino a quando i dati path_str punti a (l'originale Path).

In altre parole, ci sono due vite qui. Userò un'ipotetica sintassi di annotazione a vita del blocco nell'esempio da @ Arjan filed bug (questa risposta è basata su my response there).

fn test<'a>(s: &'a String) -> &'a str { 
    'b: { 
     let slice: &'a str = s.as_slice(); 
     slice.as_slice() 
    } 
} 

Per la seconda chiamata as_slice abbiamo self: &'b &'a str, e così Restituzioni &'b str, che è troppo breve: 'b è solo locale per test.


Come hai scoperto, la correzione ora è solo rimuovendo l'estraneo as_slice chiamata. Tuttavia, con dynamically sized types (DST), saremo in grado di scrivere impl StrSlice for str e quindi slice.as_slice()sarà restituire un &'a str, poiché non ci sarà un ulteriore livello di riferimenti (ovvero, self: &'a str).

+0

Quindi, con questa definizione equivakente di Str trait: http://is.gd/L4yATO, come mai quel tipo di firma non è una bugia? – Arjan

+0

@ Arjan Quale tipo di firma? 'fn as_slice2 <'a> (& 'un sé) -> &' a str'? – huon

+0

sì, il suo affermare che il suo reyurning qualcosa con la vita 'un ma * sé è di vita' b. O deduce che 'a <' b e questo lo rende valido? – Arjan