rust - Derivar un rasgo produce un error inesperado del compilador, pero la implementación manual funciona
clone (2)
La respuesta está enterrada en el mensaje de error:
existe el método de
clone
pero no se cumplieron los siguientes límites de rasgos:T : std::clone::Clone
Cuando deriva
Clone
(y muchos otros tipos derivados automáticamente), agrega un
Clone
enlazado en
todos
los tipos genéricos.
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.
Este código ( playground ):
#[derive(Clone)]
struct Foo<''a, T: ''a> {
t: &''a T,
}
fn bar<''a, T>(foo: Foo<''a, T>) {
foo.clone();
}
... no compila:
error: no method named `clone` found for type `Foo<''a, T>` in the current scope
--> <anon>: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 el
#[derive(Clone)]
e implemento manualmente
Clone
para
Foo
, ¡se
compila como se esperaba
!
impl<''a, T> Clone for Foo<''a, T> {
fn clone(&self) -> Self {
Foo {
t: self.t,
}
}
}
¿Que esta pasando aqui?
-
¿Hay alguna diferencia entre
#[derive()]
-impls y manuales? - ¿Es esto un error del compilador?
- ¿Algo más en lo que no pensé?
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 del patio de juegos )
Parece inusual que pueda evitar especificar el límite explícitamente, pero la respuesta de Shepmaster parece sugerir que el compilador lo inserta implícitamente, por lo que mi sugerencia es funcionalmente idéntica.