Bienvenidos sean a este post, hoy veremos algunas caracteristicas adicionales de los trait.
Limites
El lenguaje nos da la posibilidad de poder establecer un limite encima de nuestro trait, de hecho es una regla que el trait debe cumplir y este debe ser agregado al parametro de tipo de declaracion, por ejemplo podemos tener la siguiente struct:
#[derive(PartialEq)]
struct Cuatro {
x: u32,
y: i32,
z: f32,
g: f64,
}
En este caso el limite es la derive donde implementamos a PartialEq, el cual es un trait que se utiliza para comparaciones de igualdad para relaciones de equivalencia parcial, es decir que nuestro codigo solo chequeara por equivalencia parcial dentro del struct, en caso de tener un codigo que solo compare algunos parametros dentro del struct, en cambio si no lo pusieramos al momento de compilarlo nos devolveria un error porque los parametros no son iguales internamente.
Reduccion del codigo
Si bien cuando hablamos de trait dijimos que su orden natural era el struct, seguido del trait para finalmente usar el impl y definir las funciones del trait, esto no es tan asi porque si lo deseamos podemos definir el metodo en el trait, por ejemplo este es un trait valido:
trait rasgo
{
fn metodo_seguro(&self) -> bool;
}
Pero la siguiente tambien es valida:
trait rasgo
{
fn metodo_seguro(&self) -> bool { self.ejecutar() }
}
La diferencia entre ambos es como dijimos al principio, en el primer caso debemos usar un impl para definir al prototipo y en el segundo caso no es necesario porque ya esta definido, igualmente recuerden que la buena practica es la primera aunque no obligatoria 😉
Sobreescribir un metodo
Al igual que cualquier otro lenguaje tambien podemos sobreescribir (override) un metodo, inclusive un predeterminado, para verlo en accion vamos a realizar un ejemplo, para ello deben crear un nuevo proyecto que llamaremos over_ride, una vez creado el mismo iremos al archivo main.rs y modificaremos el codigo generado por el siguiente:
main.rs
trait MiRasgo
{
fn primera(&self) -> bool;
fn segunda(&self) -> bool { println!("Segunda funcion"); true }
}
struct PrimerUso;
impl MiRasgo for PrimerUso
{
fn primera(&self) -> bool
{
println!("Primera funcion de PrimerUso");
true
}
}
struct ReescribirPrimerUso;
impl MiRasgo for ReescribirPrimerUso
{
fn primera(&self) -> bool
{
println!("Primera funcion de ReescribirPrmerUso");
true
}
fn segunda(&self) -> bool
{
println!("Segunda funcion de ReescribirPrimerUso");
true
}
}
fn main()
{
let pu = PrimerUso{};
let rpu = ReescribirPrimerUso{};
pu.primera();
rpu.segunda();
}
Vamos a comentar el codigo porque tenemos varias particularidades, lo primero que tendremos es el trait que usaremos y dentro tendremos dos metodos, uno sin definir (primera) y otro definido (segunda), en ambos casos devolveremos un valor booleano, en el caso de segunda muestra un mensaje y devuelve un valor de true, despues declaramos un struct de tipo unit-like, luego tenemos un impl donde pasamos el trait del inicio y le decimos que es para el struct anteriormente declarado, en este definiremos solamente la funcion que faltaba en el trait, primera, donde pasaremos un mensaje que es la funcion de este struct y tambien devolvera un true, despues tenemos otro struct de tipo unit-like para nuevamente usar un impl donde volveremos a usar el trait y le indicamente que es para este nuevo struct pero dentro definiremos al metodo primera con otro mensaje distinto al anterior y luego redefiniremos al metodo segunda donde indicaremos otro mensaje distinto al original, en ambos casos devolveran un true, por ultimo tenemos el main donde crearemos dos objetos de los struct, despues llamaremos al metodo primera del struct PrimerUso en el primer objeto y en el segundo objeto llamaremos al metodo segunda pero esta vez del struct ReescribirPrimerUso, compilemos y veamos su salida:
tinchicus@dbn001vrt:~/lenguajes/rust/over_ride$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/over_ride`
Primera funcion de PrimerUso
Segunda funcion de ReescribirPrimerUso
tinchicus@dbn001vrt:~/lenguajes/rust/over_ride$
Como podemos ver se puede hacer la sobreescritura u override de manera sencilla, otra curiosidad que vimos en este codigo es que si bien dijimos que struct, trait e impl deben mantener un orden no es necesario en el codigo y podemos agregarlo como queramos pero siempre es mas util hacerlo en el orden correcto, tambienn hemos visto que en el trait podemos tener tanto un prototipo como una funcion definida y uno no interferira con el otro siempre y cuando definamos al prototipo con impl.
En resumen, hoy hemos visto tres caracteristica de trait, la primera es el limite que podemos establecer para nuestros trait, luego hemos visto que el impl no es 100% obligatorio, por ultimo hemos visto como sobreescribir un metodo de un trait, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
