2015-01-05 3 views
6
struct Point { 
    x: uint, 
    y: uint 
} 

struct Line<'a> { 
    start: &'a Point, 
    end: &'a Point 
} 

Qui, l'unica opzione possibile per start e end campi è quello di avere una vita uguale o più lunga della variabile Line che li contiene. Non riesco nemmeno a immaginare come si andrà usando il lifetime specificifier per dire che i campi hanno una vita più breve. Allora perché devo specificare esplicitamente la durata qui? Elision non è possibile in questa situazione e, in tal caso, perché?Perché le vite non possono essere elite in una definizione di struttura?

+0

Mentre suppongo sia possibile che Rust possa scegliere di elidere le vite in una definizione di struttura, non lo fa ora. Vedrai solo il termine 'elisione a vita 'usato per funzioni/metodi. – Shepmaster

risposta

5

Quando si definisce una struttura, non si crea una relazione tra la durata della struttura e la durata dei campi. Come si fa notare, i riferimenti nei campi hanno per vivere più a lungo della struttura.

Invece, quello che stai facendo è fornire una "vita generica" ​​che sarà specializzata quando crei la struttura. Questo è simile ad avere una struttura con un parametro di tipo:

struct Foo<T> 
    foo: T, 
} 

Quando si costruisce la struct, vite appropriate (o tipi) verrà inserito dal compilatore, e poi controlla che tutto funziona ancora fuori.

L'altra cosa è che è possibile specificare i tempi di vita rispetto gli uni agli altri:

struct Line<'a, 'b : 'a> { 
    start: &'a Point, 
    end: &'b Point 
} 

Qui, lei sta dicendo che start e end può avere diverse vite, a condizione che la durata di fine outlives la durata di inizio.

perché il compilatore non esegue l'elisione a vita per le strutture? Sembra che nel spirito di Rust a farlo

(sottolineatura mia)

Io in realtà credo che Rust tende verso esplicitazione, soprattutto quando si tratta di definire gli elementi di primo livello (come funzioni , structs).

Le regole per l'elisione a vita per le funzioni hanno uno scopo piuttosto ridotto ed erano empirically found con un alto tasso di successo (87%). Questo è stato un ottimo ritorno sull'investimento ergonomico.

Forse a un certo punto, si verificheranno elisioni simili per le strutture, ma non è stato un problema abbastanza grande eppure. Se ti senti fortemente a favore di questo, ti consiglio vivamente di chiedere un consenso sullo user forum, passando al forum degli sviluppatori, quindi alla fine facendo un RFC.

+2

Non è chiaro da questa risposta perché la vita sia * necessaria * quando si dichiara una struttura. – RajV

+0

Hai notato il commento che ho aggiunto alla tua domanda? Se ti capisco, la risposta è "perché il compilatore lo richiede". Se hai riferimenti nella tua struttura, devi specificare qual è la vita/i di tali riferimenti. Non esiste un'elisione a vita per le dichiarazioni di struct, anche se suppongo che il compilatore possa mettere automaticamente "a" per ogni vita. Per ottenere ciò, dovresti fare una richiesta di funzionalità a Rust stesso. – Shepmaster

+1

@RajV, perché non c'è un modo ovvio per andare senza di loro. I riferimenti non statici all'interno di una struct * necessariamente * indicano che dovrebbe esserci almeno un parametro lifetime, ma possono essercene di più e significherebbe una cosa diversa. –

0

Supponiamo di avere un costruttore per Line:

impl<'a> Line<'a> { 
    fn new(start: &'a Point, end: &'a Point) -> Line<'a> { // ' 
     Line { 
      start: start, 
      end: end, 
     } 
    } 
} 

new restituisce un Line<'a>. Per poter parametrizzare un tipo con una durata (come facciamo qui con Line<'a>), questo tipo deve definire i parametri di durata!Sebbene il compilatore possa definire automaticamente i parametri di durata quando necessario, è molto più facile capire che un tipo ha parametri di durata (o meno) semplicemente guardando la sua definizione nel codice sorgente.

I parametri di durata delle strutture e le enumerazioni svolgono un ruolo importante nel controllo del prestito. Lasciano che il compilatore sappia che una struttura trattiene in prestito alcuni valori. Il compilatore può quindi restituire degli errori quando si tenta di mutare un valore che ha un prestito attivo.

fn main() { 
    let mut start = Point { x: 2, y: 4 }; 
    let end = Point { x: 7, y: 10 }; 
    let line = Line::new(&start, &end); 
    start.x = 3; // error: cannot assign to `start.x` because it is borrowed 
}