rust lifetime

rust - El compilador sugiere que agregue una ''vida útil estática porque el tipo de parámetro puede no vivir lo suficiente, pero no creo que eso sea lo que quiero



lifetime (2)

Estoy tratando de implementar algo que se parece a este ejemplo mínimo:

trait Bar<T> {} struct Foo<T> { data: Vec<Box<Bar<T>>>, } impl<T> Foo<T> { fn add<U: Bar<T>>(&mut self, x: U) { self.data.push(Box::new(x)); } }

Dado que Rust por defecto es (por lo que puedo decir) paso por propiedad, mi modelo mental piensa que esto debería funcionar. El método add toma posesión del objeto x y puede mover este objeto a un Box porque conoce el tipo completo U (y no solo la Bar<T> rasgos Bar<T> ). Una vez que se haya movido a una Box , la vida útil del elemento dentro de la caja debe estar vinculada a la vida real de la caja (por ejemplo, cuando se saca del vector el objeto será destruido).

Claramente, sin embargo, el compilador no está de acuerdo (y estoy seguro que sabe un poco más que yo ...), pidiéndome que considere agregar un ''static calificador ''static vida (E0310). Estoy 99% seguro de que eso no es lo que quiero, pero no estoy exactamente seguro de lo que se supone que debo hacer.

Para aclarar lo que estoy pensando y ayudar a identificar conceptos erróneos, mi modelo mental, proveniente de un entorno de C ++, es:

  • Box<T> es esencialmente std::unique_ptr<T>
  • Sin anotaciones, las variables se pasan por valor si Copy y rvalue-reference de lo contrario
  • Con una anotación de referencia, & es más o menos const& y &mut es más o menos
  • El tiempo de vida predeterminado es el alcance léxico

pidiéndome que considere agregar un ''calificador estático de por vida (E0310). Estoy 99% seguro de que eso no es lo que quiero, pero no estoy exactamente seguro de lo que se supone que debo hacer.

Sí lo es. El compilador no quiere una referencia &''static , quiere U: ''static .

Tener U: ''static significa que U no contiene referencias con una vida útil menor que ''static . Esto es necesario porque desea colocar una instancia de U en una estructura sin vidas.

trait Bar<T> {} struct Foo<T> { data: Vec<Box<dyn Bar<T>>>, } impl<T> Foo<T> { fn add<U: Bar<T> + ''static>(&mut self, x: U) { self.data.push(Box::new(x)); } }


Mira el error completo:

error[E0310]: the parameter type `U` may not live long enough --> src/main.rs:9:24 | 8 | fn add<U: Bar<T>>(&mut self, x: U) { | -- help: consider adding an explicit lifetime bound `U: ''static`... 9 | self.data.push(Box::new(x)); | ^^^^^^^^^^^ | note: ...so that the type `U` will meet its required lifetime bounds --> src/main.rs:9:24 | 9 | self.data.push(Box::new(x)); | ^^^^^^^^^^^

Específicamente, el compilador le está haciendo saber que es posible que algún tipo arbitrario U pueda contener una referencia , y esa referencia podría dejar de ser válida:

impl<''a, T> Bar<T> for &''a str {} fn main() { let mut foo = Foo { data: vec![] }; { let s = "oh no".to_string(); foo.add(s.as_ref()); } }

Eso serían malas noticias.

Si desea una vida útil ''static o una vida útil parametrizada depende de sus necesidades. La vida útil ''static es más fácil de usar, pero tiene más restricciones. Debido a esto, es el valor predeterminado cuando declaras un objeto de rasgo en una estructura o un alias de tipo:

struct Foo<T> { data: Vec<Box<dyn Bar<T>>>, // same as // data: Vec<Box<dyn Bar<T> + ''static>>, }

Sin embargo, cuando se usa como argumento, un objeto de rasgo usa una elisión de por vida y obtiene una vida útil única:

fn foo(&self, x: Box<dyn Bar<T>>) // same as // fn foo<''a, ''b>(&''a self, x: Box<dyn Bar<T> + ''b>)

Estas dos cosas deben coincidir.

struct Foo<''a, T> { data: Vec<Box<dyn Bar<T> + ''a>>, } impl<''a, T> Foo<''a, T> { fn add<U>(&mut self, x: U) where U: Bar<T> + ''a, { self.data.push(Box::new(x)); } }

o

struct Foo<T> { data: Vec<Box<dyn Bar<T>>>, } impl<T> Foo<T> { fn add<U>(&mut self, x: U) where U: Bar<T> + ''static, { self.data.push(Box::new(x)); } }