Derivar un rasgo produce un error inesperado del comstackdor, pero la implementación manual funciona

Este código ( patio de recreo ):

#[derive(Clone)] struct Foo { t: &'a T, } fn bar(foo: Foo) { foo.clone(); } 

… no comstack:

 error: no method named `clone` found for type `Foo` in the current scope --> :7:9 |> 16 |> foo.clone(); |> ^^^^^ note: the method `clone` exists but the following trait bounds were not satisfied: `T : std::clone::Clone` help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `clone`, perhaps you need to implement it: help: candidate #1: `std::clone::Clone` 

Agregar use std::clone::Clone; no cambia nada, ya que de todos modos ya está en el preludio.

Cuando elimino #[derive(Clone)] e implemento manualmente Clone for Foo , ¡se comstack como se esperaba !

 impl Clone for Foo { fn clone(&self) -> Self { Foo { t: self.t, } } } 

¿Que esta pasando aqui?

  • ¿Hay una diferencia entre #[derive()] -impls y manuales?
  • ¿Es esto un error del comstackdor?
  • ¿Algo más en lo que no pensé?

La respuesta está enterrada en el mensaje de error:

el clone método existe pero los siguientes límites de rasgo no se cumplieron: T : std::clone::Clone

Cuando deriva Clone (y muchos otros tipos derivados automáticamente), agrega un Clone obligado en todos los tipos generics. Usando rustc -Z unstable-options --pretty=expanded , podemos ver en qué se convierte:

 impl < 'a, T: ::std::clone::Clone + 'a> ::std::clone::Clone for Foo< 'a, T> { #[inline] fn clone(&self) -> Foo< 'a, T> { match *self { Foo { t: ref __self_0_0 } => Foo{t: ::std::clone::Clone::clone(&(*__self_0_0)),}, } } } 

En este caso, el límite no es necesario porque el tipo genérico está detrás de una referencia.

Por ahora, deberá implementar Clone usted mismo. Hay un problema de rust para esto , pero es un caso relativamente raro con una solución alternativa.

Su ejemplo derivará Clone sin ningún problema si marca explícitamente que T debe implementar Clone , así:

 #[derive(Clone)] struct Foo< 'a, T: 'a> { t: &'a T, } fn bar< 'a, T: Clone>(foo: Foo< 'a, T>) { foo.clone(); } 

( Enlace de juegos )

Parece inusual que pueda evitar especificar el límite explícitamente, pero la respuesta de Shepmaster parece sugerir que el comstackdor lo inserta implícitamente, por lo que mi sugerencia es funcionalmente idéntica.