2014-03-05 11 views
5

Also, in:Was bedeutet eine Lebensdauer im Rost?

fn v1<'a> (a:~[&'a str]) -> ~[&'a str] { 
    return a; 
} 

#[test] 
fn test_can_create_struct() { 
    let x = v1("Hello World".split(' ').collect()); 
} 

Ich weiß, ich habe http://static.rust-lang.org/doc/master/guide-lifetimes.html#named-lifetimes gelesen, aber ich verstehe nicht, was dieser Code tatsächlich tut.

Die Funktion ist grundsätzlich wie ein generisches fn parametrisiert, aber mit einer Lebensdauer, ist, was ich auf dem IRC-Kanal gesagt habe, aber stellen wir uns vor, dass dies der Fall ist, und wir haben eine bestimmte Lebenszeitstruktur .

Anscheinend bin ich Aufruf implizit:

v1::<L>("Hello World".split(' ').collect()); 

..aber ich bin es nicht. Die Lebenszeit, die an diese Funktion übergeben wird, ist eine Instanz eines Lebens, es ist nicht eine Art der Lebensdauer, so dass Kommentar keinen Sinn für mich macht.

Ich meine, ich verstehe im Grunde, was los ist (denke ich): Die zurückgegebenen ~[&str] hat die gleiche Lebensdauer wie der Umfang des Anrufers, vermutlich die test_can_create_struct() Funktion. Das ist, weil (wie ich es verstehe) die Funktion v1 mit der Lebensdauer Instanz von der aufrufenden Funktion aufgerufen wird.

Sehr verwirrend.

Dann haben wir einige andere Beispiele wie: https://gist.github.com/bvssvni/8970459

Hier ist ein Fragment:

impl<'a> Data<'a> { 
    pub fn new() -> Data<'a> { 
    Data { a: None, b: None } 
    } 

    pub fn a(&'a mut self, a: int) -> State<'a, Step1> { 
    self.a = Some(a); 
    State { data: self } 
    } 
} 

hier Jetzt naiv ging ich davon aus, dass die Data<'a> bedeutet, dass die Lebensdauer Instanz für die Funktion a() gleich ist.

d. Wenn Sie einen (let blah = Data::new()) erstellen und blah.a() aufrufen, wird die Lebensdauer vom Erstellungsaufruf geerbt; d.h. das State Objekt, das zurückgegeben wird, existiert so lange wie das übergeordnete Data Objekt.

... aber anscheinend ist das auch falsch. Ich habe also keine Ahnung, was die Lebenszeitvariablen überhaupt bedeuten.

Hilfe!

+0

Lebenszeiten * sind * Teil des Typsystems; Sie sind keine Instanzen. –

Antwort

19

Der einfachste Weg, dies zu beantworten, ist, einen Schritt zurück zu machen und Sie durch das zu führen, was ein Leben eigentlich ist.

Ermöglicht eine einfache Funktion übernehmen:

fn simple_function() { 
    let a = MyFoo::new(); 
    println("{}", a); 
} 

In dieser Funktion haben wir eine Variable, a. Diese Variable lebt wie alle Variablen für eine gewisse Zeit. In diesem Fall lebt es bis zum Ende der Funktion. Wenn die Funktion endet, stirbt a. Die Lebensdauer von a kann dann so beschrieben werden, dass sie am Anfang der Funktion beginnt und am Ende der Funktion endet.

wird diese nächste Funktion nicht kompilieren:

fn broken_function() -> &MyFoo { 
    let a = MyFoo::new(); 
    return &a; 
} 

Wenn Sie &a tun, sind Sie Borgen ein Referenz-a. Die Sache mit der Kreditaufnahme ist jedoch, dass von Ihnen erwartet wird, dass Sie das, was Sie geliehen haben, zurückgeben. Rust ist diesbezüglich sehr streng und wird dir keine Hinweise geben, die du nicht zurückgeben kannst. Wenn die Sache, von der Sie Ihre Referenz ausgeliehen haben, nicht mehr existiert, können Sie die Referenz nicht mehr zurückgeben, und das ist einfach nicht möglich.

Was es für unsere broken_function bedeutet, ist, dass, weil a am Ende der Funktion stirbt, die Referenz die Funktion nicht verlassen kann, denn das würde es a überleben.

Der nächste Schritt ist das:

fn call_fn() { 
    let a = MyFoo:new(); 
    { 
    let a_ref = &a; 
    let b = lifetimed(a_ref); 

    println!("{}", *b); 
    } 
} 

fn lifetimed<'a>(foo: &'a MyFoo) -> &'a MyBar { 
    return foo.as_bar(); 
} 

Hier sind zwei Funktionen, call_fn und lifetimed, gibt es einige subtile Sachen los hier, also werde ich es brechen.

In call_fn ich zuerst eine neue Instanz von MyFoo erstellen und Zuweisen zu a dann ich einen Hinweis auf a borgen und Zuweisen zu a_ref. Die Sache mit der Kreditaufnahme ist, dass wenn Sie einen Kredit aufnehmen, die lebenslange Information von der Variable, die Sie leihen, in die Referenz selbst übertragen wird. Also jetzt a_ref, als eine Variable, hat seine eigene Lebensdauer, die beginnt und endet am Anfang und Ende des inneren Bereichs, aber der Typ a_refauch hat eine Lebensdauer, die eine über a übertragen.

Konkrete Lebensdauern können nicht benannt werden, aber wir können so tun, als könnten wir es trotzdem tun, indem wir Zahlen verwenden. Wenn die Lebensdauer von a#1 ist, dann ist der Typ von a_ref&'#1 MyFoo. Wenn wir a_ref an lifetimed übergeben, füllt der Compiler den Lebensdauerparameter 'a wie für andere Typparameter aus. lifetimed 's Rückgabetyp ist eine Referenz mit der gleichen Lebensdauer, also füllt der Compiler dort den Platz aus. Effektiv einen einzigartigen Anruf zu lifetimed(foo: &'#1 MyFoo) -> &'#1 MyBar machen.

Aus diesem Grund erscheinen Lebenszeiten in der Typparameterliste, sie sind Teil des Typsystems, und wenn die Typen nicht übereinstimmen, ist das ein Fehler. Der Compiler berechnet die Lebensdauern, die benötigt werden, damit die Funktion kompiliert werden kann, so dass Sie sich nie darum kümmern müssen, aber nicht nach der aktuellen Funktion suchen, um weitere Informationen zu erhalten. Sie müssen die Parameter verwenden, um den Compiler über die Funktion, die Sie anrufen, zu informieren, damit es weiß, dass alles in Ordnung ist.


NB: Es gibt ein Leben Sie explizit benennen. 'static Das ist die Lebensdauer von Dingen, die für die gesamte Länge des Programms dauern.

+1

Vielen Dank für Ihre Erklärung, aber, können Sie ein reales Leben Beispiel geben, wenn es notwendig ist, Lebensdauer für Funktion zu erklären? Ich kann immer noch nicht diese Funktion Anwendungsfälle zu fangen .. – gobwas

+0

Ich denke, die Verwendung von generischen Typ ist sehr verwirrend.Es fügt nur ein Tag hinzu, um einen neuen Bereich/Bereich zu erstellen, ein generischer Typ impliziert einen neuen Typ, der für jede 'a, T Kombination zB 1, T, 2, T usw. instanziiert wird und das 1, T! = 2, T ist nicht der Fall. – user1496062