reference - Iterador devolviendo elementos por referencia, problema de por vida
iterator rust (1)
Nota sobre la versión de Rust utilizada: en el momento en que se escribieron esta pregunta y respuesta, el rasgo del
Iterator
usaba genéricos; ha cambiado para usar tipos asociados y ahora se define así:
pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; … }
Y entonces la implementación incorrecta que se muestra aquí sería así:
impl<''a> Iterator for Foo { type Item = &''a u8; fn next<''a>(&''a mut self) -> Option<&''a u8>; }
En términos prácticos, esto no afecta a nada; es simplemente que
A
convierte enSelf::Item
.
La definición del rasgo del Iterator
es así:
pub trait Iterator<A> {
fn next(&mut self) -> Option<A>;
…
}
Observe cuidadosamente: fn next(&mut self) -> Option<A>
.
Esto es lo que tienes:
impl<''a> Iterator<&''a u8> for Foo {
fn next<''a>(&''a mut self) -> Option<&''a u8>;
}
Tenga en cuenta cuidadosamente: fn next<''a>(&''a mut self) -> Option<&''a u8>
.
Hay varios problemas aquí:
Has introducido un nuevo parámetro genérico
<''a>
que no debería estar allí. Para mayor comodidad y para enfatizar lo que ha sucedido aquí, doblaré el''a
definido en el bloque impl ρ₀ y el''a
definido en el método ρ₁. Ellos no son los mismos.La vida de
&mut self
es diferente de la del rasgo.La duración del tipo de devolución es diferente del rasgo: donde
A
es&''ρ₀ u8
, el tipo de devolución se usa en el lugar deA
&''ρ₁ u8
. Esperaba la vida útil concreta ρ₀ pero encontró en cambio la duración ρ₁. (No estoy seguro de qué significa exactamente el bit "encuadernado", así que me mantendré callado, por miedo a equivocarme).
Esto es lo que equivale a esto: no se puede conectar el tiempo de vida del objeto sobre el que se está iterando. En cambio, debe estar vinculado a algo del tipo para el que está implementando el rasgo. Para tomar un ejemplo, la iteración de elementos en un corte se hace creando un nuevo objeto iterador conectado al corte base, impl<''a, T> Iterator<&''a T> for Items<''a, T>
. Expresado de otra manera, la forma en que se diseñan los rasgos de iteración no es, si está produciendo referencias, para devolver algo dentro de self
, sino más bien para devolver algo dentro de otro objeto al que tiene referencia.
Para su ejemplo presumiblemente simple, debe dejar de generar referencias o modificarlas para que el objeto del iterador no contenga los datos que está iterando; deje que contenga simplemente una referencia , por ejemplo &''a [T]
o incluso algo así como Items<''a, T>
.
Tengo un problema de por vida , estoy intentando implementar un iterador que devuelva sus elementos por referencia, aquí está el código:
struct Foo {
d: [u8; 42],
pos: usize
}
impl<''a> Iterator<&''a u8> for Foo {
fn next<''a>(&''a mut self) -> Option<&''a u8> {
let r = self.d.get(self.pos);
if r.is_some() {
self.pos += 1;
}
r
}
}
fn main() {
let mut x = Foo {
d: [1; 42],
pos: 0
};
for i in x {
println!("{}", i);
}
}
Sin embargo, este código no se compila correctamente, aparece un problema relacionado con la duración de los parámetros, aquí está el error correspondiente:
$ rustc test.rs
test.rs:8:5: 14:6 error: method `next` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter
test.rs:8 fn next<''a>(&''a mut self) -> Option<&''a u8> {
test.rs:9 let r = self.d.get(self.pos);
test.rs:10 if r.is_some() {
test.rs:11 self.pos += 1;
test.rs:12 }
test.rs:13 r
...
test.rs:8:49: 14:6 note: expected concrete lifetime is the lifetime ''a as defined on the block at 8:48
test.rs:8 fn next<''a>(&''a mut self) -> Option<&''a u8> {
test.rs:9 let r = self.d.get(self.pos);
test.rs:10 if r.is_some() {
test.rs:11 self.pos += 1;
test.rs:12 }
test.rs:13 r
...
error: aborting due to previous error
¿Alguien tiene una idea de cómo solucionar este problema y aún devolver elementos por referencia?
Al menos, ¿qué significa este mensaje: vida útil esperada, pero se encontró un parámetro de vida útil consolidado ?