2016-02-29 15 views
7

Nie znalazłem żadnych reguł w dokumentacji rdzy, które wyjaśniałyby, w jaki sposób eliminacja na całe życie dotyczy zamknięć. Weźmy prosty przykład:Dlaczego firma Rust nie może określić prawidłowego okresu użytkowania w prostych zamknięciach lub w informacjach, które są sprzeczne?

fn foo(s: &str) { 
    let id = |x: &str| x; 
    println!("{}", id(s)); 
} 

fn main() { 
    foo("string"); 
} 

myślałem, że zamknięcie w funkcji foo będzie działać podobnie do następującego kodu:

fn foo(s: &str) { 
    struct Id; // A helper structure for closure 
    impl Id { 
     fn id(self: Self, x: &str) -> &str { &x } 
    } 
    let id = Id; // Creating a closure 
    println!("{}", id.id(s)); 
} 

Ten ostatni działa dobrze, ale były nie do kompilowania i produkuje długi komunikat o sprzecznych wymagań życiowych:

t3.rs:2:24: 2:25 error: cannot infer an appropriate lifetime due to conflicting requirements [E0495] 
t3.rs:2  let id = |x: &str| x; 
          ^
t3.rs:2:24: 2:25 note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 2:23... 
t3.rs:2  let id = |x: &str| x; 
          ^
t3.rs:2:24: 2:25 note: ...so that expression is assignable (expected `&str`, found `&str`) 
t3.rs:2  let id = |x: &str| x; 
          ^
<std macros>:3:11: 3:36 note: but, the lifetime must be valid for the expression at 3:10... 
<std macros>:3 print ! (concat ! ($ fmt , "\n") , $ ($ arg) *)) ; 
         ^~~~~~~~~~~~~~~~~~~~~~~~~ 
<std macros>:2:25: 2:56 note: in this expansion of format_args! 
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>) 
t3.rs:3:5: 3:27 note: in this expansion of println! (defined in <std macros>) 
<std macros>:3:11: 3:36 note: ...so type `(&&str,)` of expression is valid during the expression 
<std macros>:3 print ! (concat ! ($ fmt , "\n") , $ ($ arg) *)) ; 
         ^~~~~~~~~~~~~~~~~~~~~~~~~ 
<std macros>:2:25: 2:56 note: in this expansion of format_args! 
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>) 
t3.rs:3:5: 3:27 note: in this expansion of println! (defined in <std macros>) 
error: aborting due to previous error 

zastanawiam się, dlaczego nie można wywnioskować Rust właściwego życia w prostych zamknięć, takich jak ten, który Napisałem powyżej. Ponadto, dlaczego kompilator uważa, że ​​istnieją wymagania w zakresie konfliktu w ciągu jednego cyklu życia na przestrzeni.

+0

Zdjąć ': & str' i to działa. '& Str' nie oznacza, co myślisz, że to znaczy. Nie mam teraz czasu, aby wyjaśnić, jak powinienem być w łóżku. –

+1

Właściwie miałem na myśli "& str", ponieważ jest to konieczne w nieco bardziej złożonym przypadku. W każdym razie moje pytanie nie brzmiało, jak zrobić ten trywialny przykład do działania, ale jakie są tu zasady? Dlaczego kompilator znajduje tutaj sprzeczne wymagania? – svat

+0

@ChrisMorgan: Jeśli masz trochę czasu, byłoby wspaniale, gdybyś mógł wyjaśnić, co się dzieje. Mam wrażenie, że może to być spowodowane stwierdzeniem "dla <'a>", ale nie jest to całkiem jasne ... a brak odpowiedzi po 20 godzinach wydaje się oznaczać, że nie jestem jedynym, który nie jest pewien co się dzieje^^ –

Odpowiedz

0

Zamknięcie nie może wywnioskować okresu ważności z podpowiedzi metody. Efektywnie definiując całe życie w sygnaturze metody, powiedzmy, że jest to domyślnie 'a, a także inne życie, domyślnie 'b w zamknięciu.

Dopasuj czasy życia, które się skompilują.

fn foo<'a>(s: &'a str) { 
    let id = |x: &'a str| x; 
    println!("{}", id(s)) 
} 

fn main() { 
    foo("string"); 
} 
+0

Jestem Przepraszam, jeśli źle sformułowałem moje pytanie, ale interesowało mnie _rules_, by wyciągnąć wnioski z życia w zamknięciu, a nie jak skompilować kod. Próbowałem też wersji ze statycznym ciągiem znaków: "id (" string ")', a Rust nadal nie może poprawnie określić długości życia i spowodować ten sam błąd. Jeśli Rust nie obsługuje wnioskowania o całe życie w zamknięciach, nie mam problemu z jego jawnym określeniem, ale komunikat o błędzie mówi o _conflicting_requirements_, co uważam za bardzo mylące. – svat

2

Po określeniu typu parametru lub typ zwracany w zamknięciu, a typ jest odniesienie, kompilator ustawia błędne oczekiwania na niejawnym parametrem życia, i nie ma sposobu, aby określić parametr dożywotnia wyraźnie na zamknięcie. This is a known issue. Obejście polega na pominięciu typu parametru lub typu zwracanego i niech kompilator wnioskuje wszystko.

fn foo(s: &str) { 
    let id = |x| x; 
    println!("{}", id(s)); 
} 

fn main() { 
    foo("string"); 
} 

Jeśli trzeba jeszcze dać wskazówkę typu, można to zrobić za pomocą let wiązania wewnątrz zamknięcia:

fn foo(s: &str) { 
    let id = |x| { let y: &str = x; y }; 
    println!("{}", id(s)); 
} 

fn main() { 
    foo("string"); 
} 
Powiązane problemy