2015-11-19 13 views
9

Próbuję znaleźć powtórzenia w sekwencji iterowalnej. Ponadto chcę poznać elementy, które pojawiły się w tej sekwencji do tego momentu."Czas życia związany z niezgodnością typu" kontra "czas życia betonu" przy wypełnianiu kolekcji z zamknięcia

Stworzyłem HashMap i próbuję zadzwonić pod numer insert z zamknięcia używanego przez take_while. Do tej pory jednak nie udało mi się zmusić go do kompilacji z powodu niedopasowania typu związanego z konkretnymi/związanymi okresami życia.

Tutaj jest uproszczoną wersją mojego kodu, który wykazuje ten sam błąd:

use std::collections::HashSet; 

fn main() { 
    let mut seq = HashSet::new(); 
    let mut insert = |k| seq.insert(k); 
    (1..10).cycle().take_while(insert); 
} 

Oto błędy uzyskać:

error[E0631]: type mismatch in closure arguments 
--> src/main.rs:6:21 
    | 
5 |  let mut insert = |k| seq.insert(k); 
    |      ----------------- found signature of `fn(_) -> _` 
6 |  (1..10).cycle().take_while(insert); 
    |      ^^^^^^^^^^ expected signature of `for<'r> fn(&'r {integer}) -> _` 

error[E0271]: type mismatch resolving `for<'r> <[[email protected]/main.rs:5:22: 5:39 seq:_] as std::ops::FnOnce<(&'r {integer},)>>::Output == bool` 
--> src/main.rs:6:21 
    | 
6 |  (1..10).cycle().take_while(insert); 
    |      ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime 

Jak muszę zmienić kod na to, aby praca?

+0

ciekawy, to działa, jeśli zamknięcie jest przenoszony bezpośrednio do 'rozmowy take_while': http://is.gd/OgVK2i –

+0

@ker, to działa, bo robisz subtelnie inna sprawa - używasz niejawnego dereferencji we wzorcu, który oryginalny kod nie. –

Odpowiedz

8

Jest to w rzeczywistości błąd pożyczkowy w nieszczęściu.

Iterator<Item = T>::take_while() przyjmuje zamknięcie rodzaju FnMut(&T) -> bool - oznacza to, że przekazuje każdy element do zamknięcia przez odniesienie. Jest to całkiem naturalne, ponieważ take_while() musi być w stanie uzyskać pomyślnie przetestowany element, więc nie może przekazać go według wartości.

Oznacza to, że insert typ argumentu wywnioskować być &_, a więc HashSet „s rodzajowy parametr jest również wywnioskować jak &_. Oznacza to jednak, że próbujesz zapisać odniesienia do wartości tymczasowych uzyskanych przez iterator cycle() do struktury, która żyje znacznie dłużej. Nie jest to dozwolone przez reguły wypożyczania. Niestety, Rust nie pokazuje dokładnie tego uzasadnienia, ponieważ z jakiegoś powodu nie może wywnioskować, że typ numeryczny to i32, a także nie może wywnioskować poprawnego parametru czasu życia zamknięcia. Na tym polega twój błąd.

Zamiast tego, twoje zamknięcie powinno wyłuskać argument przed zapisaniem go w zbiorze. This works:

use std::collections::HashSet; 

fn main() { 
    let mut seq = HashSet::new(); 
    let mut insert = |&k: &i32| seq.insert(k); 
    (1..10).cycle().take_while(insert); 
} 

musiałem dodać pełną typ argumentu zbyt; jak powiedziałem powyżej, myślę, że wnioskowanie typu nie jest wystarczająco silne, aby to wydedukować.

BTW, można rzeczywiście pojawia się błąd sprawdzania pożyczyć jeśli określić rodzaj extenso:

use std::collections::HashSet; 

fn main() { 
    let mut seq = HashSet::new(); 
    let mut insert = |k: &i32| seq.insert(k); // no dereference 
    (1..10).cycle().take_while(insert); 
} 

Powyższy kod jest odpowiednikiem oryginalnego przykład z wyjątkiem wyraźnej typu adnotacji, a to prowadzi do następujących błąd:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements 
--> src/main.rs:5:43 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |           ^
    | 
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 5:22... 
--> src/main.rs:5:22 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |      ^^^^^^^^^^^^^^^^^^^^^^^ 
note: ...so that expression is assignable (expected &i32, found &i32) 
--> src/main.rs:5:43 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |           ^
note: but, the lifetime must be valid for the block suffix following statement 1 at 5:5... 
--> src/main.rs:5:5 
    | 
5 |/ let mut insert = |k: &i32| seq.insert(k); 
6 | |  (1..10).cycle().take_while(insert); 
7 | | } 
    | |_^ 
note: ...so that variable is valid at time of its declaration 
--> src/main.rs:5:9 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |   ^^^^^^^^^^ 
+2

"Musiałem również dodać cały typ argumentu, jak powiedziałem powyżej, uważam, że wnioskowanie typu nie jest wystarczająco silne, aby to wydedukować." Kilka razy spotkałem się z takimi błędami. Jest zawsze z zamknięciami w wiązaniu let. Wydaje się, że istnieje różnica w sposobie ich tworzenia.Nie określając typu parametru, który ma być referencją, wynikowe odniesienie wydaje się być wcześnie związane z czasem życia zakresu zamknięcia, natomiast określenie typu będącego odniesieniem powoduje zamknięcie z oczekiwanym wyższym czasem życia. –

Powiązane problemy