Anuncios

Bienvenidos sean a este post, hoy veremos una estructura muy particular de trait.

Anuncios

Antes de comentar sobre este tema repasemos como llamar a un metodo de un struct:

let x = MiStruct {a: 1, b: 2, c: 3};
x.sumar();
Anuncios

Y si repasamos el codigo que vimos en este post donde creamos un trait e impl generico para manejar varios tipos, en ese caso manejamos a los tipos i32 y f32, tambien vimos como el compilador sabe cual utilizar, todo este proceso es llamado dispatch estatico, y Rust posee dos tipos de dispatch:

  • estatico, el preferido por Rust
  • dinamico, el que es llamado objeto de trait
Anuncios

Para entenderlo vamos a crear un nuevo ejemplo que llamaremos despacho, una vez creado iremos al archivo main.rs y modificaremos el codigo generado por el siguiente:

main.rs

trait UnObjeto
{
	fn metodo_estatico(&self) -> String;
}

impl UnObjeto for u8
{
	fn metodo_estatico(&self) -> String
	{
		format!("u8 : {}", *self)
	}
}

impl UnObjeto for String
{
	fn metodo_estatico(&self) -> String
	{
		format!("string: {}", *self)
	}
}

fn mostrar_codigo<T: UnObjeto>(datos: T)
{
	println!("{}", datos.metodo_estatico());
}

fn main() 
{
	let v1 = 8u8;
	let v2 = "Algo de texto".to_string();

	mostrar_codigo(v1);
	mostrar_codigo(v2);
}
Anuncios
Anuncios

Primero crearemos un trait que llamaremos UnObjeto, en este declaramos un prototipo para una funcion que devolvera un valor de tipo String, luego tendremos un impl sobre el trait para los tipos u8, en este definiremos al metodo del trait donde por medio de format transformaremos el valor recibido en un tipo String y pueda ser devuelto, observen que esta vez usamos el apuntador de self, nuestro siguiente paso sera otro impl para el trait pero esta vez para los tipo String, hace exactamente lo mismo a la anterior implementacion pero pensada para los tipo String, despues tenemos una funcion llamada mostrar_codigo, en este utilizaremos uno de tipo generico pero que estara relacionado a nuestro trait UnObjeto, es decir que este generico sera de este tipo, despues tendremos un argumento que sera tambien generico pero que estara relacionado al trait, lo siguiente sera usar el metodo implementado (metodo_estatico) para el valor que recibimos,, por ultimo tenemos el main donde definiremos dos variables para los datos que manejamos y luego usamos la funcion mostrar_codigo para ver los valores, compilemos y veamos su salida:

tinchicus@dbn001vrt:~/lenguajes/rust/despacho$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/despacho`
u8 : 8
string: Algo de texto
tinchicus@dbn001vrt:~/lenguajes/rust/despacho$
Anuncios

Aqui tenemos un codigo que puede manejar dos tipos de datos, este seria un caso de dispatch estatico, con esto funcionando vamos a modificar el codigo de main.rs de la sigueinte manera:

main.rs

trait UnObjeto
{
	fn metodo_dinamico(&self) -> String;
}

impl UnObjeto for u8
{
	fn metodo_dinamico(&self) -> String
	{
		format!("u8 : {}", *self)
	}
}

impl UnObjeto for String
{
	fn metodo_dinamico(&self) -> String
	{
		format!("string: {}", *self)
	}
}

fn mostrar_codigo(datos: &dyn UnObjeto)
{
	println!("{}", datos.metodo_dinamico());
}

fn main() 
{
	let v1 = 8u8;
	let v2 = "Algo de texto".to_string();

	mostrar_codigo(&v1 as &dyn UnObjeto);
	mostrar_codigo(&v2 as &dyn UnObjeto);
}
Anuncios
Anuncios

El trait y los impl son iguales a los que vimos en el codigo anterior pero la unica diferencia es el nombre que pasamos de metodo_estatico a metodo_dinamico, el resto es exactamente lo mismo, la magia viene ahora, en este caso la funcion cambio un poco, lo primero que hicimos fue eliminar el tipo generico que relacionabamos con nuestro trait, la otra diferencia es que pasamos el operador de referencia pero seguido de la palabra dyn y el nombre del trait que usaremos como tipo, la palabra dyn es para indicar que todas las llamados a los metodos implementados en el trait seran dispatch de tipo dinamico, en el bloque tenemos lo mismo que vimos anteriormente, por ultimo en el main tenemos un par de modificaciones, estas son al momento de llamar a nuestra funcion donde pasaremos cada una de las variables antes definidas pero esta vez con un as para indicar que seran del tipo del trait y nuevamente volveremos a usar dyn para lo que comentamos anteriormente, si lo compilan deberan obtener la misma salida anterior.

Anuncios

En resumen, hoy hemos visto que es un objeto de trait, para ser mas exacto hemos visto a los dos tipos de dispatch que usa Rust, el de tipo estatico que es el preferido por el lenguaje y el de tipo dinamico que es el verdadero objeto de trait, tambien hemos visto un ejemplo donde primero aplicamos el dispatch estatico y luego el tipo dinamico, espero les haya sido util 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.

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50