Bienvenidos sean a este post, hoy veremos una tecnica mas para los trait y genericos.
En el post anterior vimos como podiamos utilizar a los trait con genericos para poder minimizarlo y asi hacer un codigo mas reutilizable pero al final de cuentas hemos terminado haciendo un impl para cada tipo viendo como es una pseudo sobrecarga en el lenguaje, pero esto se puede mejorar con la clausura where tal como vimos en este post, para ello debemos hacer unas pequeñas modificaciones en nuestro codigo, en el archivo main.rs al comienzo de este agregaremos el siguiente bloque:
extern crate num;
use std::ops::{Add, Mul};
use num::FromPrimitive;
Primero importaremos al crate num la cual nos permitira manejar una coleccion de tipos numericos y trait para Rust, despues volveremos a usar la clase libreria standard de la cual usaremos a Add y Mul, este ultimo lo vimos en este post, pero resumiendo esta nos permitiran las operaciones de suma y multiplicacion para nuestros tipos genericos respectivamente, por ultimo tenemos una clase de num llamada FromPrimitive pero ya hablaremos luego, lo siguiente sera eliminar o comentar las implementaciones y reemplazarlas por la siguiente:
impl<T> Calcular<T> for Forma<T>
where T: Copy + FromPrimitive + Add<Output = T> + Mul<Output = T>,
{
fn calc(&self) -> T
{
let dos = T::from_u8(2).expect("No se puede crear el 2");
self.linea_uno * dos + self.linea_dos * dos
}
}
Observen que ahora utilizamos al generico en la definicion del impl, el nombre del Trait y del struct, si visitan el post anterior observaran que impl no llevaba nada y tanto en el trait como en el struct pasabamos el tipo que iba a manejar, pero aqui agregamos el where donde usamos a T y luego una serie de instrucciones, veamos cada una de ellas:
- Copy, copia el valor que le pasamos
- FromPrimitive, nos permite convertir un numero en un valor, el anteriormente copiado
- Add, es para que podamos aplicar el operador de suma en tipos genericos
- Mul, similar al anterior pero para el signo de multiplicacion
Despues tenemos la funcion pero esta vez no solamente le decimos que devuelva un generico sino que tambien agregamos una nueva variable, esta es para reemplazar el valor directo de 2 de la formula por un valor que podemos pasar en la siguiente formula la cual sera encargada de devolver el valor, no solamente hara eso sino que tambien nos devolvera un mensaje en caso de que no se pueda crear este valor, por ultimo tenemos la formula de perimetro que vinimos usando hasta ahora, el resto seguira siendo el mismo que vinimos utilizando, antes de probarlo veamos como quedo el nuevo codigo:
main.rs
extern crate num;
use std::ops::{Add, Mul};
use num::FromPrimitive;
struct Forma<T>
{
linea_uno: T,
linea_dos: T,
}
trait Calcular<T>
{
fn calc(&self) -> T;
}
impl<T> Calcular<T> for Forma<T>
where T: Copy + FromPrimitive + Add<Output = T> + Mul<Output = T>,
{
fn calc(&self) -> T
{
let dos = T::from_u8(2).expect("No se puede crear el 2");
self.linea_uno * dos + self.linea_dos * dos
}
}
fn main()
{
let peri_int = Forma { linea_uno: 5, linea_dos: 12 };
let peri_flt = Forma { linea_uno: 5.1f32, linea_dos: 12.3f32 };
println!(
"Linea uno = {}, Linea dos = {}, Perimetro = {}",
peri_int.linea_uno, peri_int.linea_dos, peri_int.calc()
);
println!(
"Linea uno = {}, Linea dos = {}, Perimetro = {}",
peri_flt.linea_uno, peri_flt.linea_dos, peri_flt.calc()
);
}
Pero antes de compilarlo debemos declarar la dependencia num para que no nos devuelva ningun error, para ello deben ir al archivo Cargo.toml y en la seccion de dependendas debemos agregar la siguiente linea:
num = "*"
La cual hara que al momento de compilarlo se descarguen todas las dependencias necesarias, veamos como queda el codigo del archivo:
Cargo.toml
[package]
name = "rasgo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
num = "*"
Con todo esto indicado podemos pasar a compilarlo y ver cual es su salida:
tinchicus@dbn001vrt:~/lenguajes/rust/rasgo$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/rasgo`
Linea uno = 5, Linea dos = 12, Perimetro = 34
Linea uno = 5.1, Linea dos = 12.3, Perimetro = 34.8
tinchicus@dbn001vrt:~/lenguajes/rust/rasgo$
Como pueden ver la misma funcion la pudimos usar para dos tipos distintos de datos pero en este caso usamos un solo tipo de operacion (perimetro) y no tenemos para el ovalo pero mas adelante veremos como mejorarlo, por lo pronto esta es una forma basica de poder tener todo bajo el uso de genericos.
En resumen, hoy hemos visto como usar where de los genericos para tener una implementacion de impl pero de tipo generico, hemos visto las breves modificaciones para tenerlo activo, asi como un repaso de como habilitar dependencias para nuestros codigos, 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.


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