El compilador sugiere que agregue una "vida útil estática" porque es posible que el tipo de parámetro no dure lo suficiente, pero no creo que eso sea lo que quiero.

Resuelto Robert Mason asked hace 8 años • 2 respuestas

Estoy intentando implementar algo parecido 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 (hasta donde yo sé) pasa por propiedad, mi modelo mental cree que esto debería funcionar. El addmétodo toma posesión del objeto xy puede mover este objeto a Boxporque conoce el tipo completo U(y no solo el rasgo Bar<T>). Una vez trasladado a Box, la vida útil del artículo dentro de la caja debe estar vinculada a la vida útil real de la caja (por ejemplo, cuandopop() se elimine el vector, el objeto será destruido).

Sin embargo, claramente el compilador no está de acuerdo (y estoy seguro de que sabe un poco más que yo...) y me pide que considere agregar un'static calificador 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.

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

  • Box<T>Es esencialstd::unique_ptr<T>
  • Sin ninguna anotación, las variables se pasan por valor siCopy y rvalue-reference en caso contrario
  • Con una anotación de referencia, &es aproximadamente const&y &mutes aproximadamente&
  • La vida útil predeterminada es el alcance léxico.
Robert Mason avatar Oct 15 '16 06:10 Robert Mason
Aceptado

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 informa que es posible que algún tipo arbitrario U contenga 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());
    }
}

Serían malas noticias.

Si desea una 'staticvida útil o una vida útil parametrizada, depende de sus necesidades. La 'staticvida útil 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 utiliza como argumento, un objeto de rasgo utiliza la elisión de duración y obtiene una duración ú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));
    }
}
Shepmaster avatar Oct 15 '2016 00:10 Shepmaster

pidiéndome que considere agregar un 'calificador de por vida estático (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 &'staticreferencia, quiere U: 'static.

Tener U: 'staticsignifica que Uno contiene referencias con una vida útil inferior a 'static. Esto es necesario porque desea colocar una Uinstancia en una estructura sin duración.

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));
    }
}
mcarton avatar Oct 15 '2016 00:10 mcarton