mi sono imbattuto in un problema che semplifica nella seguente:Posso scrivere un Iterator che si muta e quindi produce un riferimento in se stesso?
struct MyIter {
vec: Vec<i8>,
}
fn fill_with_useful_data(v: &mut Vec<i8>) {
/* ... */
}
impl<'a> Iterator for MyIter {
type Item = &'a [i8];
fn next(&mut self) -> Option<&'a [i8]> {
fill_with_useful_data(&mut self.vec);
Some(&self.vec)
}
}
fn main() {
for slice in (MyIter { vec: Vec::new() }) {
println!("{}", slice);
}
}
Questo genera l'errore:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:9:6
|
9 | impl<'a> Iterator for MyIter {
| ^^ unconstrained lifetime parameter
L'idea è che l'iteratore fa un gruppo di lavoro che riflette nei suoi campi e al ogni passo, produce un riferimento in sé al codice chiamante. In questo caso, potrei modellarlo come se producessi una copia dello stato anziché il riferimento, ma facciamo finta che ciò non sia possibile o solo fastidioso.
Intuitivamente questo non dovrebbe essere un problema perché il correttore prestito può garantire che .next()
non è chiamato nuovamente mentre il riferimento dato può ancora essere utilizzato per controllare lo stato del iteratore, ma il tratto Iterator
non sembra prevedere quel genere di cose direttamente. Anche con alcune permutazioni come il solo aggrapparsi a un riferimento al vettore nell'iteratore stesso o rendere l'iteratore un riferimento o qualcosa per ottenere le vite nel tipo precedente, non riesco a ottenere nulla oltre il controllore del prestito.
Ho letto il blogpost "Iterators yielding mutable references" ma non sono sicuro se/come si applica al mio problema che non coinvolge riferimenti mutabili.
Va bene, ho appena smesso di implementare 'Iterator' e ho creato il mio ciclo for con una macro. Non pensavo a come '.collect()' non avrebbe funzionato. – ben
Questo è anche utile per gli attraversamenti in cui non è possibile utilizzare il ciclo 'for': 'while lasciare Some (elemento) = iter.next() {...' – bluss
Per riferimento futuro, questo tipo di iteratore ('fn successivo (& 'un sé) ') viene spesso definito come * uno streaming iteratore *. Alcuni esempi di discussioni [1] (https://users.rust-lang.org/t/returning-borrowed-values-from-an-iterator/1096), [2] (https://www.reddit.com/r/ruggine/commenti/2t1rxx/more_general_iterator_trait /) e una [cassa che ne implementa una forma] (https://github.com/sfackler/streaming-iterator). – Shepmaster