2013-10-06 13 views
7

Jeśli mam funkcję zwracającą funkcję:żywotność wyrażenia lambda w rdzy

fn<'r, T> (p : T) -> (&'r fn(&'r str) -> ~[(T,int)]) { 
    return |s| ~[(p, 0)] 
} 

Jednak to nie wydają się działać, pojawia się następujący (nieco tautologiczną) Błąd:

playground.rs:10:8: 10:29 error: cannot infer an appropriate lifetime due to conflicting requirements 
playground.rs:10   return |s| ~[(p, 0i)] 
         ^~~~~~~~~~~~~~~~~~~~~ 
playground.rs:9:70: 11:5 note: first, the lifetime cannot outlive the block at 9:70... 
playground.rs:9  pub fn result<'r, T>(p : T) -> (&'r fn(&'r str) -> ~[(T, int)]){ 
playground.rs:10   return |s| ~[(p, 0i)] 
playground.rs:11  } 
playground.rs:10:8: 10:29 note: ...due to the following expression 
playground.rs:10   return |s| ~[(p, 0i)] 
         ^~~~~~~~~~~~~~~~~~~~~ 
playground.rs:9:70: 11:5 note: but, the lifetime must be valid for the lifetime &'r as defined on the block at 9:70... 
playground.rs:9  pub fn result<'r, T>(p : T) -> (&'r fn(&'r str) -> ~[(T, int)]){ 
playground.rs:10   return |s| ~[(p, 0i)] 
playground.rs:11  } 
playground.rs:10:8: 10:29 note: ...due to the following expression 
playground.rs:10   return |s| ~[(p, 0i)] 
         ^~~~~~~~~~~~~~~~~~~~~ 
error: aborting due to previous error 

Sądzę, że mówi się, że czas trwania zwrotu podpisu funkcji i wartość zwracana nie pasują do siebie. Jednak nie jestem pewien, jak opisać lambdę przez całe życie, aby to działało.

Odpowiedz

12

Jest to częsty błąd w rdzeniu, myśląc, że parametry życia faktycznie wpływają na życie.

Nie, pozwalają kompilatorowi tylko na to, że referencja zwrócona z funkcji trwa przez pewien czas. Tak czy inaczej byłoby to prawdą, ale teraz kompilator też o tym wie i może zabezpieczyć więcej kodu. Jest to konsekwencją Rusta jedynie przeprowadzającego analizę lokalną (patrząc na jedną funkcję na raz).

W tym przypadku tworzysz zamknięcie stosu. Jak sugeruje nazwa, na stosie jest tworzone zamknięcie stosu, a następnie zwracane do stosu. Jest to podobne do tego kodu C:

int *foo() { int a = 5; return &a; } 

Oczywiste jest, że wskaźnik (lub "odniesienia") do a jest nieprawidłowy moment powrotu. Właśnie temu zapobiega Rust.

W tym przypadku żywotność zamknięcia stosu trwa przez czas działania funkcji, ale parametr czasu życia wymaga, aby trwał dłużej (chociaż nie ma nic do powiedzenia, jak długo to jest dokładnie), a zatem niezgodność błąd.

Podstawowa zasada jest taka, że ​​jeśli masz parametry cyklu życia dla funkcji, potrzebujesz każdego parametru w pozycji na liście argumentów i typu zwracanego, w przeciwnym razie prawdopodobnie robisz coś nie tak.

Jeśli naprawdę chcesz zwrócić zamknięcie, musisz użyć zamknięcia sterty, ~fn (&str) -> ~[(T, int)], ponieważ jest ono przydzielane na stercie i może być przekazywane w bardziej swobodny sposób (choć nadal nie jest kopiowane).