2015-11-19 9 views
9

Sto cercando di trovare ripetizioni in una sequenza iterabile. Inoltre, voglio conoscere gli elementi che si sono verificati in quella sequenza fino a quel momento.Tipo mismatch "bound lifetime parameter" vs "concrete lifetime" durante il riempimento di una raccolta da una chiusura

Ho creato un HashMap e sto provando a chiamare insert su di esso da una chiusura utilizzata da take_while. Tuttavia, finora non sono riuscito a farlo compilare a causa di mancate corrispondenze di tipo relative a vite concatenate/vincolate.

Ecco una versione semplificata del mio codice che espone lo stesso errore:

use std::collections::HashSet; 

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

Qui ci sono gli errori che ottengo:

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 

Come ho bisogno di modificare il codice per poter lavoro?

+0

curioso, funziona se la chiusura viene spostato direttamente nel 'chiamata take_while': http://is.gd/OgVK2i –

+0

@ker, che funziona perché si sta facendo una cosa leggermente diversa - stai usando un implicito dereferenziamento nel modello, che il il codice originale no. –

risposta

8

Questo è in realtà un errore di prestito sotto mentite spoglie.

Iterator<Item = T>::take_while() accetta una chiusura di tipo FnMut(&T) -> bool - ovvero, passa ogni elemento alla chiusura per riferimento. Questo è praticamente naturale perché take_while() deve essere in grado di fornire l'elemento testato con successo, quindi non può passarlo per valore.

Ciò significa che insert tipo argomento è dedotta per essere &_, e così HashSet s' parametro generico è anche dedurre come &_. Tuttavia, ciò significa che stai tentando di memorizzare riferimenti a valori temporanei generati dall'iteratore cycle() in una struttura che vive molto più a lungo. Questo non è permesso dalle regole del prestito. Sfortunatamente, Rust non mostra esattamente questo ragionamento perché per qualche motivo non può dedurre che il tipo numerico sia i32 e che non possa inferire il parametro di durata corretto per la chiusura. Questo è il tuo errore.

Invece, la chiusura dovrebbe discernere l'argomento prima di memorizzarlo sul set. 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); 
} 

ho dovuto aggiungere il tipo completo dell'argomento troppo; come ho detto sopra, penso che l'inferenza di tipo non sia abbastanza potente per dedurlo.

proposito, si può effettivamente ottenere l'errore prestito controllo se si specifica il tipo in modo esplicito:

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); 
} 

Il codice di cui sopra è equivalente al tuo esempio originale tranne che per il tipo di annotazione esplicita, e il risultato è il seguente errore:

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

"Ho dovuto aggiungere anche il tipo completo dell'argomento, come ho detto sopra, penso che l'inferenza di tipo non sia abbastanza potente per dedurlo." Mi sono imbattuto in tali errori un paio di volte. È sempre con chiusure in una let binding. Sembra che ci sia una differenza nel modo in cui vengono istanziati.Non specificando il tipo di parametro come riferimento, il riferimento dedotto risultante sembra essere legato in anticipo alla durata dell'ambito di chiusura, mentre specificando il tipo di riferimento si traduce in una chiusura con la durata di vita più elevata prevista. –

Problemi correlati