¿Cómo escribo un iterador que devuelve referencias a sí mismo?
Tengo problemas para expresar la vida útil del valor de retorno de una Iterator
implementación. ¿Cómo puedo compilar este código sin cambiar el valor de retorno del iterador? Me gustaría que devuelva un vector de referencias.
Es obvio que no estoy usando correctamente el parámetro de vida útil, pero después de probar varias formas simplemente me di por vencido y no tengo idea de qué hacer con él.
use std::iter::Iterator;
struct PermutationIterator<T> {
vs: Vec<Vec<T>>,
is: Vec<usize>,
}
impl<T> PermutationIterator<T> {
fn new() -> PermutationIterator<T> {
PermutationIterator {
vs: vec![],
is: vec![],
}
}
fn add(&mut self, v: Vec<T>) {
self.vs.push(v);
self.is.push(0);
}
}
impl<T> Iterator for PermutationIterator<T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&T>> {
'outer: loop {
for i in 0..self.vs.len() {
if self.is[i] >= self.vs[i].len() {
if i == 0 {
return None; // we are done
}
self.is[i] = 0;
self.is[i - 1] += 1;
continue 'outer;
}
}
let mut result = vec![];
for i in 0..self.vs.len() {
let index = self.is[i];
result.push(self.vs[i].get(index).unwrap());
}
*self.is.last_mut().unwrap() += 1;
return Some(result);
}
}
}
fn main() {
let v1: Vec<_> = (1..3).collect();
let v2: Vec<_> = (3..5).collect();
let v3: Vec<_> = (1..6).collect();
let mut i = PermutationIterator::new();
i.add(v1);
i.add(v2);
i.add(v3);
loop {
match i.next() {
Some(v) => {
println!("{:?}", v);
}
None => {
break;
}
}
}
}
( Enlace al patio de juegos )
error[E0261]: use of undeclared lifetime name `'a`
--> src/main.rs:23:22
|
23 | type Item = Vec<&'a T>;
| ^^ undeclared lifetime
Hasta donde tengo entendido, lo que quieres es que el iterador devuelva un vector de referencias a sí mismo, ¿verdad? Desafortunadamente, no es posible en Rust.
Este es el rasgo recortado Iterator
:
trait Iterator {
type Item;
fn next(&mut self) -> Option<Item>;
}
Tenga en cuenta que no existe una conexión de por vida entre &mut self
y Option<Item>
. Esto significa que ese next()
método no puede devolver referencias al propio iterador. Simplemente no se puede expresar la vida útil de las referencias devueltas. Esta es básicamente la razón por la que no pudiste encontrar una manera de especificar la vida útil correcta; se habría visto así:
fn next<'a>(&'a mut self) -> Option<Vec<&'a T>>
excepto que este no es un next()
método válido para Iterator
el rasgo.
Estos iteradores (los que pueden devolver referencias a sí mismos) se denominan iteradores de transmisión . Puedes encontrar más aquí , aquí y aquí , si quieres.
Actualizar. Sin embargo, puede devolver una referencia a alguna otra estructura desde su iterador; así es como funcionan la mayoría de los iteradores de colecciones. Podría verse así:
pub struct PermutationIterator<'a, T> {
vs: &'a [Vec<T>],
is: Vec<usize>
}
impl<'a, T> Iterator for PermutationIterator<'a, T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&'a T>> {
...
}
}
Observe cómo la vida útil 'a
ahora se declara en impl
bloque. Está bien hacerlo (de hecho, es obligatorio) porque necesita especificar el parámetro de vida útil en la estructura. Entonces puedes usar el mismo tipo de devolución 'a
tanto en Item
como en next()
. Nuevamente, así es como funcionan la mayoría de los iteradores de colecciones.
La respuesta de @VladimirMatveev es correcta en cuanto a cómo explica por qué su código no se puede compilar. En pocas palabras, dice que un iterador no puede generar valores prestados desde sí mismo.
Sin embargo, puede generar valores prestados de otra cosa. Esto es lo que se logra con Vec
and Iter
: the Vec
posee los valores y the Iter
es solo un contenedor capaz de generar referencias dentro de Vec
.
Aquí tienes un diseño que logra lo que deseas. El iterador es, como con Vec
y Iter
, solo un contenedor sobre otros contenedores que realmente poseen los valores.
use std::iter::Iterator;
struct PermutationIterator<'a, T: 'a> {
vs : Vec<&'a [T]>,
is : Vec<usize>
}
impl<'a, T> PermutationIterator<'a, T> {
fn new() -> PermutationIterator<'a, T> { ... }
fn add(&mut self, v : &'a [T]) { ... }
}
impl<'a, T> Iterator for PermutationIterator<'a, T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&'a T>> { ... }
}
fn main() {
let v1 : Vec<i32> = (1..3).collect();
let v2 : Vec<i32> = (3..5).collect();
let v3 : Vec<i32> = (1..6).collect();
let mut i = PermutationIterator::new();
i.add(&v1);
i.add(&v2);
i.add(&v3);
loop {
match i.next() {
Some(v) => { println!("{:?}", v); }
None => {break;}
}
}
}
(Patio de juegos)
No relacionado con su problema inicial. Si fuera solo yo, me aseguraría de que todos los vectores prestados se tomen a la vez. La idea es eliminar las llamadas repetidas add
y pasar directamente todos los vectores prestados en la construcción:
use std::iter::{Iterator, repeat};
struct PermutationIterator<'a, T: 'a> {
...
}
impl<'a, T> PermutationIterator<'a, T> {
fn new(vs: Vec<&'a [T]>) -> PermutationIterator<'a, T> {
let n = vs.len();
PermutationIterator {
vs: vs,
is: repeat(0).take(n).collect(),
}
}
}
impl<'a, T> Iterator for PermutationIterator<'a, T> {
...
}
fn main() {
let v1 : Vec<i32> = (1..3).collect();
let v2 : Vec<i32> = (3..5).collect();
let v3 : Vec<i32> = (1..6).collect();
let vall: Vec<&[i32]> = vec![&v1, &v2, &v3];
let mut i = PermutationIterator::new(vall);
}
(Patio de juegos)
( EDITAR : se cambió el diseño del iterador para tomar a Vec<&'a [T]>
en lugar de a Vec<Vec<&'a T>>
. Es más fácil llevar una referencia al contenedor que construir un contenedor de referencias).