Rusty Full Stack
El blog para los amantes de Rust, Ionic y Vuejs
El blog para los amantes de Rust, Ionic y Vuejs
Este es el "segundo capítulo" de nuestra mini-serie sobre cómo podemos organizar nuestro código en Rust, si quieres leer nuestro primer capítulo, puedes hacerlo en el siguiente enlace:
Organizar Código en Rust - Paquetes y Librerías.
Los módulos en Rust no son más que agrupaciones que podemos de funcionalidades que podemos hacer en nuestro código, con la ventaja que nos permite definir un "alcance" sobre que partes de nuestro código pueden accederse de forma pública (por otras funciones o estructuras) y cuales son de carácter privado (solamente puede accederse desde el módulo mismo).
Si el concepto anterior de ha parecido un poco confuso, no te vayas a desanimar, lo vamos a entender mejor haciendo un pequeño ejemplo 🤓, sin embargo, antes vamos a hablar de los pasos que realiza Rust para poder encontrar un módulo en nuestro código, nuevamente te comento que esta mini-serie está basada en el séptimo capítulo del libro oficial de Rust "Managing Growing Projects with Packages, Crates, and Modules", si tienes la oportunidad, te recomiendo darle una leída.
Las reglas que Rust sigue para encontrar módulos dentro de nuestro paquete, crate o proyecto son:
Ok, sé que a lo mejor son muchas reglas para aprenderse 🥵, pero verás que todo es bastante sencillo cuando hagamos un pequeño ejemplo.
Puedes ver el código terminado del ejemplo en el repositorio en github dando click a este enlace.
En este ejemplo vamos a crear un programa en Rust utilizando módulos, nuestro programa tratará de simular una caja de supermercado y tendrá las siguientes funcionalidades:
Hay muchas formas de poder hacer el programa, pero para nuestro ejemplo vamos a crear dos módulos.
Empecemos creando nuestro paquete, en cualquier carpeta de tu elección ejecuta los siguientes comandos.
cargo new caja-supermercado
cd caja-supermercado
Podríamos crear un nuevo crate o dividir cada módulo en crates por separado, pero esta vez me gustaría mostrarte la creación de los módulos desde el crate root, es decir desde src/lib.rs, ya en el siguiente post hablaremos como dividir nuestros módulos en varios archivos, pero por el momento empezaremos por lo básico.
Dentro la carpeta caja-supermercado/src, creemos un archivo en blanco y le llamaremos lib.rs, nuestro paquete debería de verse así:
Ahora creemos el primer módulo dentro de src/lib.rs, recuerda que nuestros módulos debemos de definirlos utilizando la palabra reservada mod.
// src/lib.rs
mod compra {
}
Con el bloque de código anterior acabamos de definir un módulo llamado "compra", en este módulo vamos a crear las funciones para agregar o quitar un item, también para ver los items y el total de compra, agreguemos las definiciones que vamos a utilizar, empecemos definiendo la estructura "Item" que habíamos mencionado anteriormente y las funciones.
// src/lib.rs
mod compra {
#[derive(Debug)]
struct Item {
nombre: String, // Nombre del item
precio_unitario: f32, // Precio Unitario del item
cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agregara un item a un vector con todos los items de la compra
}
fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
}
fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
}
fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el total a pagar de todos los items de la compra
0.0
}
}
En el bloque de código anterior, estamos creando un módulo al que hemos llamado "compra" y le hemos colocado la definición de las funciones para el manejo de los items de la caja.
Ahora vamos a agregarle el código de cada una de las funciones, no he colocado mucho comentario porque no es el objetivo de este post, el objetivo es que veamos como funcionan los módulos.
// src/lib.rs
mod compra {
#[derive(Debug)]
struct Item {
nombre: String, // Nombre del item
precio_unitario: f32, // Precio Unitario del item
cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agrega un item a un vector con todos los items de la compra
items_compra.push(item);
}
fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
items_compra.remove(indice);
}
fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
for (index, item) in items_compra.iter().enumerate() {
let subtotal = item.cantidad * item.precio_unitario;
println!("[{}]. {} - Cantidad: {} - Precio U: ${} - Subtotal: ${}", index, item.nombre, item.cantidad, item.precio_unitario, subtotal);
}
}
fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el totla a pagar de todos los items de la compra
let mut total_compra: f32 = 0.0;
for item in items_compra {
total_compra = total_compra + (item.cantidad * item.precio_unitario);
}
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
total_compra = (total_compra * y).round() / y;
total_compra
}
}
Con lo anterior hemos creado el modulo de compra y sus funciones internas, ahora intentemos agregarlo en nuestro src/main.rs, por el momento solamente intentemos utilizar el módulo con la palabra reservada use e intentemos ejecutarlo. Es importante comentar que el nombre del crate en este caso es el nombre de nuestro paquete.
// src/main.rs
use caja_supermercado::compra;
fn main() {
println!("Usando el modulo");
}
Si ahora intentamos compilar nuestro programa vamos a ver que el compilador terminará mostrándonos un error, para compilar el programa ejecutemos en una terminal (dentro de la carpeta caja-supermercado)
cargo build
Dentro del error encontrarás el siguiente mensaje:
Este mensaje quiere decir que desde nuestro crate root (src/main.rs), no es posible utilizar ninguna función del módulo, esto es debido a que ha sido declarado de forma privada, para poder utilizarlo fuera de src/lib.rs, debemos definirlo de forma pública, agreguemos la palabra reservada pub antes de mod, de la siguiente manera:
// src/lib.rs
pub mod compra {
#[derive(Debug)]
struct Item {
nombre: String, // Nombre del item
precio_unitario: f32, // Precio Unitario del item
cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agrega un item a un vector con todos los items de la compra
items_compra.push(item);
}
fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
items_compra.remove(indice);
}
fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
for (index, item) in items_compra.iter().enumerate() {
let subtotal = item.cantidad * item.precio_unitario;
println!("[{}]. {} - Cantidad: {} - Precio U: ${} - Subtotal: ${}", index, item.nombre, item.cantidad, item.precio_unitario, subtotal);
}
}
fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el totla a pagar de todos los items de la compra
let mut total_compra: f32 = 0.0;
for item in items_compra {
total_compra = total_compra + (item.cantidad * item.precio_unitario);
}
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
total_compra = (total_compra * y).round() / y;
total_compra
}
}
Si ahora compilamos nuestro programa, veremos muchos warnings que iremos resolviendo poco a poco, pero lo importante es que nuestro programa compilara sin problemas:
cargo build
Genial, ahora que ha compilado modifiquemos un poco nuestro src/main.rs para intentar utilizar una de las funciones del módulo, en este caso hagamos una modificación simple para declarar un vector el cual contendrá todos los items de la compra.
// src/main.rs
// Indiquemos al modulo que queremos utilizar la estructura Item definida en el modulo
use caja_supermercado::compra::Item;
fn main() {
let mut items_compra: Vec<Item> = Vec::new();
}
Si ahora intentamos compilar nuestro programa con:
cargo build
Veremos un nuevo error:
Pero si habíamos declarado nuestro módulo de manera pública ¿por qué nos ha lanzado el error 😣?, acá entra en juego lo que habíamos comentado anteriormente sobre los alcances de un módulo, aunque le hayamos indicado a Rust que queremos hacer el módulo público, es necesario indicar explícitamente qué funciones, estructuras, etc, queremos que otras partes del código también tengan acceso público, al analizar lo que queremos que haga el módulo, podemos constatar que queremos que tanto la estructura, sus atributos y demás funciones sean públicas por lo que haremos que cada una de ellas pueda ser utilizada externamente de esta forma en src/lib.rs
// src/lib.rs
pub mod compra {
#[derive(Debug)]
pub struct Item {
pub nombre: String, // Nombre del item
pub precio_unitario: f32, // Precio Unitario del item
pub cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
pub fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agrega un item a un vector con todos los items de la compra
items_compra.push(item);
}
pub fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
items_compra.remove(indice);
}
pub fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
for (index, item) in items_compra.iter().enumerate() {
let subtotal = item.cantidad * item.precio_unitario;
println!("[{}]. {} - Cantidad: {} - Precio U: ${} - Subtotal: ${}", index, item.nombre, item.cantidad, item.precio_unitario, subtotal);
}
}
pub fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el totla a pagar de todos los items de la compra
let mut total_compra: f32 = 0.0;
for item in items_compra {
total_compra = total_compra + (item.cantidad * item.precio_unitario);
}
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
total_compra = (total_compra * y).round() / y;
total_compra
}
}
Si ahora compilamos nuestro programa, veremos siempre algunos warning que ya resolveremos, pero lo importante es que nuestro programa ahora sí logra compilar.
cargo build
Perfecto! ahora vamos a hacer nuestra caja un poco más interactiva, primero vamos a decirle a Rust que vamos a usar todas las funciones del módulo de compra, para ello podemos utilizar use caja_supermercado::*, o individualmente como será nuestro caso dentro de src/main.rs, para que veas la sintáxis para importar más de una función o estructura (colocándolo dentro de {}).
// src/main.rs
use caja_supermercado::compra::{Item, agregar_item, quitar_item, mostrar_items, total_compra};
fn main() {
let mut items_compra: Vec<Item> = Vec::new();
}
Si lo compilas verás que aunque existen warnings, nuestro programa sigue compilando bien. Ahora si agreguemos un menu y su interacción, esto lo podríamos hacer dentro de otro módulo, pero por el momento vamos a crear las funciones dentro de src/main.rs.
// src/main.rs
use std::io::stdin;
use caja_supermercado::compra::{Item, agregar_item, quitar_item, mostrar_items, total_compra};
fn mostrar_menu() {
println!("OPCIONES:");
println!("1. Agregar Item");
println!("2. Quitar Item");
println!("3. Mostrar Items");
println!("4. Total a Pagar");
println!("5. Realizar Pago");
println!("6. Cancelar Compra y Salir");
println!("Selecciona una opcion");
}
fn manejar_agregar_item(items_compra: &mut Vec<Item>) {
println!("En Construccion");
}
fn manejar_quitar_item(items_compra: &mut Vec<Item>) {
println!("En Construccion");
}
fn manejar_realizar_pago() {
println!("En Construccion");
}
fn main() {
// Creamos un vector para llevar el registro de los items de la compra
let mut items_compra: Vec<Item> = Vec::new();
// Iniciamos un loop en el cual vamos a preguntar al usuario la accion a realizar
// Dependiendo de sus seeleccion vamos a realizar una tarea, todas ellas dependeran
// de funciones dentro del modulo "compra"
loop {
mostrar_menu();
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
match opcion_seleccionada {
1 => manejar_agregar_item(&mut items_compra), // Agregar un item
2 => manejar_quitar_item(&mut items_compra), // quitar un item
3 => mostrar_items(&items_compra), // mostrar todos los items y sus indices
4 => println!("Total a pagar: ${}", total_compra(&items_compra)), // mostrando el total a pagar
5 => manejar_realizar_pago(), // realizar el pago
6 => break, // terminando el programa
_ => println!("Opcion Invalida") // la opcion no es valida, el programa continua
};
}
println!("Programa Finalizado");
}
Si ahora ejecutamos nuestro programa con:
cargo run
Veremos algunos warnings que ya resolveremos en un momento pero lo importante es que veremos el menu de opciones que tenemos disponible, si seleccionamos alguna (a excepcion de la opcion 6, 3, 4 y 7) veremos que nos mostrará un mensaje que dice "En Construccion", y el programa continuará mostrando el menú de opciones, si seleccionamos la opción 6 el programa terminará.
Ya nuestro programa va tomando forma 😍, ahora vamos a utilizar nuestro módulo de compra para ir haciendo "la cuenta" en nuestra caja virtual. Agreguemos el siguiente código en src/main.rs para agregar y quitar items de la cuenta.
// src/main.rs
use std::io::stdin;
use caja_supermercado::compra::{Item, agregar_item, quitar_item, mostrar_items, total_compra};
fn mostrar_menu() {
println!("OPCIONES:");
println!("1. Agregar Item");
println!("2. Quitar Item");
println!("3. Mostrar Items");
println!("4. Total a Pagar");
println!("5. Realizar Pago");
println!("6. Cancelar Compra y Salir");
println!("Selecciona una opcion");
}
fn manejar_agregar_item(items_compra: &mut Vec<Item>) {
// Solicitando que el usuario registre los datos del item
// por facilidad no hemos colocado validaciones, en un ambiente
// laboral SI debes colocarlas.
// Quiza no es el input mas optimo del planeta pero sirve a manera
// de ejemplo de uso de modulos
let mut input: String = String::new();
println!("Escribe los detalles del Item");
println!("NOMBRE:");
stdin().read_line(&mut input).unwrap();
let nombre = input.replace("\n", "").replace("\r", "");
println!("CANTIDAD:");
input = String::new();
stdin().read_line(&mut input).unwrap();
let cantidad = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
println!("PRECIO UNITARIO: ");
input = String::new();
stdin().read_line(&mut input).unwrap();
let precio_unitario = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
// Creando el item con la estructura que importamos de nuestro modulo
let item: Item = Item {
nombre,
precio_unitario,
cantidad
};
// Agregando el item a la compra
agregar_item(items_compra, item);
println!("Item Agregado!");
}
fn manejar_quitar_item(items_compra: &mut Vec<Item>) {
// mostrando los items par que el usuario pueda saber cual quitar
// REUTILIZANDO NUESTRO MODULO !!!
println!("Selecciona el indice que quieres quitar");
mostrar_items(items_compra);
// Obteniendo el itema a eliminar
let mut input: String = String::new();
stdin().read_line(&mut input).unwrap();
// limpiando el input de la terminal
let indice = input.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
// Eliminando el item utilizando la funcion dentro del modulo de compra
quitar_item(items_compra, indice);
println!("Item eliminado");
}
fn manejar_realizar_pago() {
println!("En Construccion");
}
fn main() {
// Creamos un vector para llevar el registro de los items de la compra
let mut items_compra: Vec<Item> = Vec::new();
// Iniciamos un loop en el cual vamos a preguntar al usuario la accion a realizar
// Dependiendo de sus seeleccion vamos a realizar una tarea, todas ellas dependeran
// de funciones dentro del modulo "compra"
loop {
mostrar_menu();
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
match opcion_seleccionada {
1 => manejar_agregar_item(&mut items_compra), // Agregar un item
2 => manejar_quitar_item(&mut items_compra), // quitar un item
3 => mostrar_items(&items_compra), // mostrar todos los items y sus indices
4 => println!("Total a pagar: ${}", total_compra(&items_compra)), // mostrando el total a pagar
5 => manejar_realizar_pago(), // realizar el pago
6 => break, // terminando el programa
_ => println!("Opcion Invalida") // la opcion no es valida, el programa continua
};
}
println!("Programa Finalizado");
}
Si ahora ejecutamos nuestro programa veremos que ya no hay warnings y que somos capaces de agregar items (opcion 1) y mostrarlos (opcion 3) 😎
También podemos quitar items (recuerda que no hemos colocado validaciones, por lo que asegúrate que existan items, en un ambiente laborar RECUERDA colocarlas)
Incluso también muestra el total a pagar 🤑 !!, en la siguiente imagen he agregado algunos items para mostrar algún total.
Ahora lo único que nos queda por hacer es agregar el módulo de pago (el cual lo simularemos), te había mencionado que los alcances en los módulos también pueden ser privados, un módulo de pago podría ser un buen candidato a contener algunas funciones de las cuales no queremos que código externo tenga acceso a ello por seguridad, por ejemplo los métodos de transferencia bancaria o pago con tarjeta porque pueden contener acceso a servicios externos bastante críticos en temas de seguridad, por lo que vamos a abstraer un poco el funcionamiento del pago y manejarlo de una forma más segura.
Anteriormente habíamos mencionado que nuestro módulo de pagos permitirá al usuario realizar el pago de tres formas:
Agreguemos el módulo siempre dentro de src/lib.rs, por facilidad de lectura lo pondremos antes del modulo de "compra", en realidad el orden en este caso no es tan importante, también por el momento dejaremos todo en un contexto privado.
Vamos a crear un enum, el cual nos permitirá indicarle a nuestro programa el método de pago elegido por el cliente y una función general de pago.
// src/lib.rs
mod pago {
enum MetodoDePago {
Efectivo,
Tarjeta,
TransferenciaBancaria,
}
struct ResultadoPago {
metodo_pago: String, // La descripcion del metodo de pago
fue_exitoso: bool, // true si el pago se pudo hacer o false si no se pudo hacer
cambio: f32, // Cambio a devolver al cliente.
}
fn pagar(metodo_de_pago: MetodoDePago, monto_a_pagar: f32, recibido_del_cliente: f32, tarjeta: &str) -> ResultadoPago{
// El parametro metodo_de_pago es la forma de pago elegida por el cliente.
// El parametro monto_a_pagar es el total a pagar de la compra.
// recibido_del_cliente es la cantidad de dinero recibida del cliente, si no es efectivo, es igual al monto a pagar
// tarjeta, es el numero de tarjeta del cliente, si el pago es en efectivo o por transferencia, no es necesario, puede ser cualquiera
}
fn pago_en_efectivo(monto_a_pagar: f32, recibido_del_cliente: f32) -> ResultadoPago {
// Si el pago es en efectivo, se calculara el cambio a devolver al cliente
}
fn pago_con_tarjeta(monto_a_pagar: f32, numero_tarjeta: &str) -> ResultadoPago {
// Si el pago es con tarjeta, simularemos el resultado
}
fn pago_por_transferencia_bancaria(monto_a_pagar: f32) -> ResultadoPago {
// Si el pago es via transferencia, simularemos que solamente necesitamos la cuenta del supermercado
// la cual seria la cuenta a recibir el dinero y tambien simularemos el resultado de la transferencia
// Esta cuenta supondriamos que es secreta
}
}
pub mod compra {
#[derive(Debug)]
pub struct Item {
pub nombre: String, // Nombre del item
pub precio_unitario: f32, // Precio Unitario del item
pub cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
pub fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agrega un item a un vector con todos los items de la compra
items_compra.push(item);
}
pub fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
items_compra.remove(indice);
}
pub fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
for (index, item) in items_compra.iter().enumerate() {
let subtotal = item.cantidad * item.precio_unitario;
println!("[{}]. {} - Cantidad: {} - Precio U: ${} - Subtotal: ${}", index, item.nombre, item.cantidad, item.precio_unitario, subtotal);
}
}
pub fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el totla a pagar de todos los items de la compra
let mut total_compra: f32 = 0.0;
for item in items_compra {
total_compra = total_compra + (item.cantidad * item.precio_unitario);
}
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
total_compra = (total_compra * y).round() / y;
total_compra
}
}
No intentes compilar el programa porque te mostrará algunos errores que vamos a corregir en un momento. Quisiera que vieras las definiciones del método de pago, por el momento todas están privadas, ahora es buen momento de detenernos un poco a pensar si queremos que todas nuestras funciones y estructuras sean públicas o queremos que algunas queden de forma privada.
Ahora pongamos como público lo que vimos que debe ser público y privado lo que debe ser privado, también completemos cada método del módulo de pagos en src/lib.rs.
// src/lib.rs
pub mod pago {
pub enum MetodoDePago {
Efectivo,
Tarjeta,
TransferenciaBancaria,
}
pub struct ResultadoPago {
pub metodo_pago: String, // La descripcion del metodo de pago
pub fue_exitoso: bool, // true si el pago se pudo hacer o false si no se pudo hacer
pub cambio: f32, // Cambio a devolver al cliente.
}
pub fn pagar(metodo_de_pago: MetodoDePago, monto_a_pagar: f32, recibido_del_cliente: f32, tarjeta: &str) -> ResultadoPago{
// El parametro metodo_de_pago es la forma de pago elegida por el cliente.
// El parametro monto_a_pagar es el total a pagar de la compra.
// recibido_del_cliente es la cantidad de dinero recibida del cliente, si no es efectivo, es igual al monto a pagar
// tarjeta, es el numero de tarjeta del cliente, si el pago es en efectivo o por transferencia, no es necesario, puede ser cualquiera
// Ahora, dependiendo del metodo de pago elegido por el cliente, invocamos las funciones privadas, esto puede hacerse
// porque estan dentro del mismo alcance de este metodo.
let resultado = match metodo_de_pago {
MetodoDePago::Efectivo => pago_en_efectivo(monto_a_pagar, recibido_del_cliente),
MetodoDePago::Tarjeta => pago_con_tarjeta(monto_a_pagar, tarjeta),
MetodoDePago::TransferenciaBancaria => pago_por_transferencia_bancaria(monto_a_pagar)
};
resultado
}
fn pago_en_efectivo(monto_a_pagar: f32, recibido_del_cliente: f32) -> ResultadoPago {
// Si el pago es en efectivo, se calculara el cambio a devolver al cliente
ResultadoPago {
metodo_pago: String::from("En Efectivo"),
fue_exitoso: true,
cambio: recibido_del_cliente - monto_a_pagar
}
}
fn pago_con_tarjeta(monto_a_pagar: f32, numero_tarjeta: &str) -> ResultadoPago {
// Si el pago es con tarjeta, simularemos el resultado
// Aca se estaria procesando todo aquello critico a nivel de seguridad.
println!("Realizando el pago con el servicio de tarjeta credito/debito");
println!("Monto a pagar: {}", monto_a_pagar);
println!("Tarjeta: {}", numero_tarjeta);
//Ahora simulamos el resultado
ResultadoPago {
metodo_pago: String::from("Tarjeta"),
fue_exitoso: true,
cambio: 0.0
}
}
fn pago_por_transferencia_bancaria(monto_a_pagar: f32) -> ResultadoPago {
// Si el pago es via transferencia, simularemos que solamente necesitamos la cuenta del supermercado
// la cual seria la cuenta a recibir el dinero y tambien simularemos el resultado de la transferencia
// Esta cuenta supondriamos que es secreta
// Aca se estaria procesando todo aquello critico a nivel de seguridad.
println!("Realizando las conexiones y transferencias con el banco");
println!("Monto a pagar: {}", monto_a_pagar);
println!("Cuenta Bancaria Secreta (o no tanto jejeej): 123456789-0");
//Ahora simulamos el resultado
ResultadoPago {
metodo_pago: String::from("Transferencia Bancaria"),
fue_exitoso: true,
cambio: 0.0
}
}
}
pub mod compra {
#[derive(Debug)]
pub struct Item {
pub nombre: String, // Nombre del item
pub precio_unitario: f32, // Precio Unitario del item
pub cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
pub fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agrega un item a un vector con todos los items de la compra
items_compra.push(item);
}
pub fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
items_compra.remove(indice);
}
pub fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
for (index, item) in items_compra.iter().enumerate() {
let subtotal = item.cantidad * item.precio_unitario;
println!("[{}]. {} - Cantidad: {} - Precio U: ${} - Subtotal: ${}", index, item.nombre, item.cantidad, item.precio_unitario, subtotal);
}
}
pub fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el totla a pagar de todos los items de la compra
let mut total_compra: f32 = 0.0;
for item in items_compra {
total_compra = total_compra + (item.cantidad * item.precio_unitario);
}
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
total_compra = (total_compra * y).round() / y;
total_compra
}
}
Si compilamos con nuestro programa con:
cargo build
vemos que ahora sí compila sin problemas, pero ahora agreguemos el nuevo módulo en nuestro crate root (src/main.rs) recuerda que debemos utilizar la palabra reservada use.
// src/main.rs
use std::io::stdin;
use caja_supermercado::compra::{Item, agregar_item, quitar_item, mostrar_items, total_compra};
use caja_supermercado::pago::{MetodoDePago, ResultadoPago, pagar};
fn mostrar_menu() {
println!("OPCIONES:");
println!("1. Agregar Item");
println!("2. Quitar Item");
println!("3. Mostrar Items");
println!("4. Total a Pagar");
println!("5. Realizar Pago");
println!("6. Cancelar Compra y Salir");
println!("Selecciona una opcion");
}
fn manejar_agregar_item(items_compra: &mut Vec<Item>) {
// Solicitando que el usuario registre los datos del item
// por facilidad no hemos colocado validaciones, en un ambiente
// laboral SI debes colocarlas.
// Quiza no es el input mas optimo del planeta pero sirve a manera
// de ejemplo de uso de modulos
let mut input: String = String::new();
println!("Escribe los detalles del Item");
println!("NOMBRE:");
stdin().read_line(&mut input).unwrap();
let nombre = input.replace("\n", "").replace("\r", "");
println!("CANTIDAD:");
input = String::new();
stdin().read_line(&mut input).unwrap();
let cantidad = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
println!("PRECIO UNITARIO: ");
input = String::new();
stdin().read_line(&mut input).unwrap();
let precio_unitario = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
// Creando el item con la estructura que importamos de nuestro modulo
let item: Item = Item {
nombre,
precio_unitario,
cantidad
};
// Agregando el item a la compra
agregar_item(items_compra, item);
println!("Item Agregado!");
}
fn manejar_quitar_item(items_compra: &mut Vec<Item>) {
// mostrando los items par que el usuario pueda saber cual quitar
// REUTILIZANDO NUESTRO MODULO !!!
println!("Selecciona el indice que quieres quitar");
mostrar_items(items_compra);
// Obteniendo el itema a eliminar
let mut input: String = String::new();
stdin().read_line(&mut input).unwrap();
// limpiando el input de la terminal
let indice = input.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
// Eliminando el item utilizando la funcion dentro del modulo de compra
quitar_item(items_compra, indice);
println!("Item eliminado");
}
fn manejar_realizar_pago() {
println!("En Construccion");
}
fn main() {
// Creamos un vector para llevar el registro de los items de la compra
let mut items_compra: Vec<Item> = Vec::new();
// Iniciamos un loop en el cual vamos a preguntar al usuario la accion a realizar
// Dependiendo de sus seeleccion vamos a realizar una tarea, todas ellas dependeran
// de funciones dentro del modulo "compra"
loop {
mostrar_menu();
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
match opcion_seleccionada {
1 => manejar_agregar_item(&mut items_compra), // Agregar un item
2 => manejar_quitar_item(&mut items_compra), // quitar un item
3 => mostrar_items(&items_compra), // mostrar todos los items y sus indices
4 => println!("Total a pagar: ${}", total_compra(&items_compra)), // mostrando el total a pagar
5 => manejar_realizar_pago(), // realizar el pago
6 => break, // terminando el programa
_ => println!("Opcion Invalida") // la opcion no es valida, el programa continua
};
}
println!("Programa Finalizado");
}
No hemos hecho más que indicarle a nuestro crate raíz de la existencia del módulo de pagos, hagamos un chequeo rápido para ver si tenemos todo sin romperse.
cargo check
A parte de algunos warnings porque no hemos utilizado todavía nada del módulo de pagos se ve que el programa podría compilar satisfactoriamente, ahora sí, agreguemos la funcionalidad del pago en nuestra función manejar_realizar_pago. En src/main.rs
// src/main.rs
use std::io::stdin;
use caja_supermercado::compra::{Item, agregar_item, quitar_item, mostrar_items, total_compra};
use caja_supermercado::pago::{MetodoDePago, ResultadoPago, pagar};
fn mostrar_menu() {
println!("OPCIONES:");
println!("1. Agregar Item");
println!("2. Quitar Item");
println!("3. Mostrar Items");
println!("4. Total a Pagar");
println!("5. Realizar Pago");
println!("6. Cancelar Compra y Salir");
println!("Selecciona una opcion");
}
fn manejar_agregar_item(items_compra: &mut Vec<Item>) {
// Solicitando que el usuario registre los datos del item
// por facilidad no hemos colocado validaciones, en un ambiente
// laboral SI debes colocarlas.
// Quiza no es el input mas optimo del planeta pero sirve a manera
// de ejemplo de uso de modulos
let mut input: String = String::new();
println!("Escribe los detalles del Item");
println!("NOMBRE:");
stdin().read_line(&mut input).unwrap();
let nombre = input.replace("\n", "").replace("\r", "");
println!("CANTIDAD:");
input = String::new();
stdin().read_line(&mut input).unwrap();
let cantidad = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
println!("PRECIO UNITARIO: ");
input = String::new();
stdin().read_line(&mut input).unwrap();
let precio_unitario = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
// Creando el item con la estructura que importamos de nuestro modulo
let item: Item = Item {
nombre,
precio_unitario,
cantidad
};
// Agregando el item a la compra
agregar_item(items_compra, item);
println!("Item Agregado!");
}
fn manejar_quitar_item(items_compra: &mut Vec<Item>) {
// mostrando los items par que el usuario pueda saber cual quitar
// REUTILIZANDO NUESTRO MODULO !!!
println!("Selecciona el indice que quieres quitar");
mostrar_items(items_compra);
// Obteniendo el itema a eliminar
let mut input: String = String::new();
stdin().read_line(&mut input).unwrap();
// limpiando el input de la terminal
let indice = input.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
// Eliminando el item utilizando la funcion dentro del modulo de compra
quitar_item(items_compra, indice);
println!("Item eliminado");
}
fn manejar_realizar_pago(items_compra: &mut Vec<Item>) {
let monto_a_pagar = total_compra(items_compra);
println!("Monto a Pagar: ${}", monto_a_pagar);
println!("Selecciona el metodo de pago.");
println!("1. En Efectivo");
println!("2. Tarjeta");
println!("3. Transferencia Bancaria");
let mut recibido_del_cliente = 0.0;
let mut tarjeta = String::from("N/A");
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
let metodo_de_pago = match opcion_seleccionada {
1 => MetodoDePago::Efectivo,
2 => MetodoDePago::Tarjeta,
3 => MetodoDePago::TransferenciaBancaria,
_ => MetodoDePago::Efectivo // por facilidad
};
if opcion_seleccionada == 1 {
// El metodo de pago es efectivo, necesitamos saber cuanto recibimos del cliente
println!("Monto Recibido del Cliente:");
let mut recibido: String = String::new();
stdin().read_line(&mut recibido).unwrap();
recibido_del_cliente = recibido.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
}
if opcion_seleccionada == 2 {
println!("Num. De Tarjeta:");
// El metodo de pago es con tarjeta, necesitamos saber el numero
let mut input: String = String::new();
stdin().read_line(&mut input).unwrap();
tarjeta = input.replace("\n", "").replace("\r", "");
}
let resultado_del_pago: ResultadoPago = pagar(metodo_de_pago, monto_a_pagar, recibido_del_cliente, &tarjeta);
if resultado_del_pago.fue_exitoso {
println!("El pago fue exitoso");
println!("Metodo de Pago: {}", resultado_del_pago.metodo_pago);
println!("Cambio: ${}", resultado_del_pago.cambio);
} else {
println!("Hubo un problema procesando el pago, intentalo de nuevo");
}
}
fn main() {
// Creamos un vector para llevar el registro de los items de la compra
let mut items_compra: Vec<Item> = Vec::new();
// Iniciamos un loop en el cual vamos a preguntar al usuario la accion a realizar
// Dependiendo de sus seeleccion vamos a realizar una tarea, todas ellas dependeran
// de funciones dentro del modulo "compra"
loop {
mostrar_menu();
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
match opcion_seleccionada {
1 => manejar_agregar_item(&mut items_compra), // Agregar un item
2 => manejar_quitar_item(&mut items_compra), // quitar un item
3 => mostrar_items(&items_compra), // mostrar todos los items y sus indices
4 => println!("Total a pagar: ${}", total_compra(&items_compra)), // mostrando el total a pagar
5 => manejar_realizar_pago(&mut items_compra), // realizar el pago
6 => break, // terminando el programa
_ => println!("Opcion Invalida") // la opcion no es valida, el programa continua
};
}
println!("Programa Finalizado");
}
Ahora si corremos nuestro programa veremos que la opción de pago ahora está habilitada!! 🤠
cargo run
Genial!! Ya nuestro programa está en muy buena forma, algo que quiero que notes es que luego del pago, no estamos borrando el saldo ni los items, por lo que te permitirá pagar más de una vez, en un mundo laboral, esto sería un gravísimo problema, pero para suerte nuestra, este es tan solo un ejemplo de uso de módulos por lo que podremos así 😎
Podríamos dejar el programa hasta acá, per me gustaría que tratásemos ahora de utilizar funciones del método de pago directamente en nuestro método de "compra" y de esta forma mostrarte que podemos utilizar funciones entre módulos.
Vamos a modificar el módulo de "compra" en src/lib.rs
// src/lib.rs
pub mod pago {
pub enum MetodoDePago {
Efectivo,
Tarjeta,
TransferenciaBancaria,
}
pub struct ResultadoPago {
pub metodo_pago: String, // La descripcion del metodo de pago
pub fue_exitoso: bool, // true si el pago se pudo hacer o false si no se pudo hacer
pub cambio: f32, // Cambio a devolver al cliente.
}
pub fn pagar(metodo_de_pago: MetodoDePago, monto_a_pagar: f32, recibido_del_cliente: f32, tarjeta: &str) -> ResultadoPago{
// El parametro metodo_de_pago es la forma de pago elegida por el cliente.
// El parametro monto_a_pagar es el total a pagar de la compra.
// recibido_del_cliente es la cantidad de dinero recibida del cliente, si no es efectivo, es igual al monto a pagar
// tarjeta, es el numero de tarjeta del cliente, si el pago es en efectivo o por transferencia, no es necesario, puede ser cualquiera
// Ahora, dependiendo del metodo de pago elegido por el cliente, invocamos las funciones privadas, esto puede hacerse
// porque estan dentro del mismo alcance de este metodo.
let resultado = match metodo_de_pago {
MetodoDePago::Efectivo => pago_en_efectivo(monto_a_pagar, recibido_del_cliente),
MetodoDePago::Tarjeta => pago_con_tarjeta(monto_a_pagar, tarjeta),
MetodoDePago::TransferenciaBancaria => pago_por_transferencia_bancaria(monto_a_pagar)
};
resultado
}
fn pago_en_efectivo(monto_a_pagar: f32, recibido_del_cliente: f32) -> ResultadoPago {
// Si el pago es en efectivo, se calculara el cambio a devolver al cliente
let mut cambio = recibido_del_cliente - monto_a_pagar;
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
cambio = (cambio * y).round() / y;
ResultadoPago {
metodo_pago: String::from("En Efectivo"),
fue_exitoso: true,
cambio
}
}
fn pago_con_tarjeta(monto_a_pagar: f32, numero_tarjeta: &str) -> ResultadoPago {
// Si el pago es con tarjeta, simularemos el resultado
// Aca se estaria procesando todo aquello critico a nivel de seguridad.
println!("Realizando el pago con el servicio de tarjeta credito/debito");
println!("Monto a pagar: {}", monto_a_pagar);
println!("Tarjeta: {}", numero_tarjeta);
//Ahora simulamos el resultado
ResultadoPago {
metodo_pago: String::from("Tarjeta"),
fue_exitoso: true,
cambio: 0.0
}
}
fn pago_por_transferencia_bancaria(monto_a_pagar: f32) -> ResultadoPago {
// Si el pago es via transferencia, simularemos que solamente necesitamos la cuenta del supermercado
// la cual seria la cuenta a recibir el dinero y tambien simularemos el resultado de la transferencia
// Esta cuenta supondriamos que es secreta
// Aca se estaria procesando todo aquello critico a nivel de seguridad.
println!("Realizando las conexiones y transferencias con el banco");
println!("Monto a pagar: {}", monto_a_pagar);
println!("Cuenta Bancaria Secreta (o no tanto jejeej): 123456789-0");
//Ahora simulamos el resultado
ResultadoPago {
metodo_pago: String::from("Transferencia Bancaria"),
fue_exitoso: true,
cambio: 0.0
}
}
}
pub mod compra {
use crate::pago;
#[derive(Debug)]
pub struct Item {
pub nombre: String, // Nombre del item
pub precio_unitario: f32, // Precio Unitario del item
pub cantidad: f32, // Cantidad a comprar del item, es float porque pueden ser fracciones de unidades, como kilos
}
pub fn agregar_item(items_compra: &mut Vec<Item>, item: Item) {
// Agrega un item a un vector con todos los items de la compra
items_compra.push(item);
}
pub fn quitar_item(items_compra: &mut Vec<Item>, indice: usize) {
// Quitara un item del array a partir de un indice
items_compra.remove(indice);
}
pub fn mostrar_items(items_compra: &Vec<Item>) {
// Mostrando los items y el indice
for (index, item) in items_compra.iter().enumerate() {
let subtotal = item.cantidad * item.precio_unitario;
println!("[{}]. {} - Cantidad: {} - Precio U: ${} - Subtotal: ${}", index, item.nombre, item.cantidad, item.precio_unitario, subtotal);
}
}
pub fn total_compra(items_compra: &Vec<Item>) -> f32 {
// Devolvera el totla a pagar de todos los items de la compra
let mut total_compra: f32 = 0.0;
for item in items_compra {
total_compra = total_compra + (item.cantidad * item.precio_unitario);
}
// redondeando a dos decimales
let y = 10i32.pow(2) as f32;
total_compra = (total_compra * y).round() / y;
total_compra
}
pub fn pagar_compra(metodo_de_pago: pago::MetodoDePago, monto_a_pagar: f32, recibido_del_cliente: f32, tarjeta: &str) -> pago::ResultadoPago{
// El parametro metodo_de_pago es la forma de pago elegida por el cliente.
// El parametro monto_a_pagar es el total a pagar de la compra.
// recibido_del_cliente es la cantidad de dinero recibida del cliente, si no es efectivo, es igual al monto a pagar
// tarjeta, es el numero de tarjeta del cliente, si el pago es en efectivo o por transferencia, no es necesario, puede ser cualquiera
// Ahora, dependiendo del metodo de pago elegido por el cliente, invocamos las funciones privadas, esto puede hacerse
// porque estan dentro del mismo alcance de este metodo.
let resultado = pago::pagar(metodo_de_pago, monto_a_pagar, recibido_del_cliente, tarjeta);
resultado
}
}
Si te fijas, dentro del modulo de "compra" estamos utilizando un use.
Rust permite esto para acortar un poco los paths a ser utilizados
y ahora cambiemos un poco nuestro src/main.rs para utilizar la función de pago del módulo de compra:
// src/main.rs
use std::io::stdin;
use caja_supermercado::pago::{MetodoDePago, ResultadoPago};
use caja_supermercado::compra::{Item, agregar_item, quitar_item, mostrar_items, total_compra, pagar_compra};
fn mostrar_menu() {
println!("OPCIONES:");
println!("1. Agregar Item");
println!("2. Quitar Item");
println!("3. Mostrar Items");
println!("4. Total a Pagar");
println!("5. Realizar Pago");
println!("6. Cancelar Compra y Salir");
println!("Selecciona una opcion");
}
fn manejar_agregar_item(items_compra: &mut Vec<Item>) {
// Solicitando que el usuario registre los datos del item
// por facilidad no hemos colocado validaciones, en un ambiente
// laboral SI debes colocarlas.
// Quiza no es el input mas optimo del planeta pero sirve a manera
// de ejemplo de uso de modulos
let mut input: String = String::new();
println!("Escribe los detalles del Item");
println!("NOMBRE:");
stdin().read_line(&mut input).unwrap();
let nombre = input.replace("\n", "").replace("\r", "");
println!("CANTIDAD:");
input = String::new();
stdin().read_line(&mut input).unwrap();
let cantidad = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
println!("PRECIO UNITARIO: ");
input = String::new();
stdin().read_line(&mut input).unwrap();
let precio_unitario = input.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
// Creando el item con la estructura que importamos de nuestro modulo
let item: Item = Item {
nombre,
precio_unitario,
cantidad
};
// Agregando el item a la compra
agregar_item(items_compra, item);
println!("Item Agregado!");
}
fn manejar_quitar_item(items_compra: &mut Vec<Item>) {
// mostrando los items par que el usuario pueda saber cual quitar
// REUTILIZANDO NUESTRO MODULO !!!
println!("Selecciona el indice que quieres quitar");
mostrar_items(items_compra);
// Obteniendo el itema a eliminar
let mut input: String = String::new();
stdin().read_line(&mut input).unwrap();
// limpiando el input de la terminal
let indice = input.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
// Eliminando el item utilizando la funcion dentro del modulo de compra
quitar_item(items_compra, indice);
println!("Item eliminado");
}
fn manejar_realizar_pago(items_compra: &mut Vec<Item>) {
let monto_a_pagar = total_compra(items_compra);
println!("Monto a Pagar: ${}", monto_a_pagar);
println!("Selecciona el metodo de pago.");
println!("1. En Efectivo");
println!("2. Tarjeta");
println!("3. Transferencia Bancaria");
let mut recibido_del_cliente = 0.0;
let mut tarjeta = String::from("N/A");
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
let metodo_de_pago = match opcion_seleccionada {
1 => MetodoDePago::Efectivo,
2 => MetodoDePago::Tarjeta,
3 => MetodoDePago::TransferenciaBancaria,
_ => MetodoDePago::Efectivo // por facilidad
};
if opcion_seleccionada == 1 {
// El metodo de pago es efectivo, necesitamos saber cuanto recibimos del cliente
println!("Monto Recibido del Cliente:");
let mut recibido: String = String::new();
stdin().read_line(&mut recibido).unwrap();
recibido_del_cliente = recibido.replace("\n", "").replace("\r", "").parse::<f32>().unwrap();
}
if opcion_seleccionada == 2 {
println!("Num. De Tarjeta:");
// El metodo de pago es con tarjeta, necesitamos saber el numero
let mut input: String = String::new();
stdin().read_line(&mut input).unwrap();
tarjeta = input.replace("\n", "").replace("\r", "");
}
let resultado_del_pago: ResultadoPago = pagar_compra(metodo_de_pago, monto_a_pagar, recibido_del_cliente, &tarjeta);
if resultado_del_pago.fue_exitoso {
println!("El pago fue exitoso");
println!("Metodo de Pago: {}", resultado_del_pago.metodo_pago);
println!("Cambio: ${}", resultado_del_pago.cambio);
} else {
println!("Hubo un problema procesando el pago, intentalo de nuevo");
}
}
fn main() {
// Creamos un vector para llevar el registro de los items de la compra
let mut items_compra: Vec<Item> = Vec::new();
// Iniciamos un loop en el cual vamos a preguntar al usuario la accion a realizar
// Dependiendo de sus seeleccion vamos a realizar una tarea, todas ellas dependeran
// de funciones dentro del modulo "compra"
loop {
mostrar_menu();
// Obtenemos la opcion que selecciona el usuario
let mut opcion: String = String::new();
stdin().read_line(&mut opcion).unwrap();
// limpiando el input de la terminal
let opcion_seleccionada = opcion.replace("\n", "").replace("\r", "").parse::<usize>().unwrap();
match opcion_seleccionada {
1 => manejar_agregar_item(&mut items_compra), // Agregar un item
2 => manejar_quitar_item(&mut items_compra), // quitar un item
3 => mostrar_items(&items_compra), // mostrar todos los items y sus indices
4 => println!("Total a pagar: ${}", total_compra(&items_compra)), // mostrando el total a pagar
5 => manejar_realizar_pago(&mut items_compra), // realizar el pago
6 => break, // terminando el programa
_ => println!("Opcion Invalida") // la opcion no es valida, el programa continua
};
}
println!("Programa Finalizado");
}
Si ejecutamos ahora nuestro programa, veremos que todo sigue funcionando tal cual lo hemos construido!! 😃
A lo mejor nuestro programa no es perfecto, porque hay muchas validaciones que hemos obviado por facilidad del ejemplo, como una tarea voluntaria puedes agregarlas y perfeccionar nuestro programa 😊
Si quieres ver el código completo de nuestro ejemplo puedes hacerlo desde el repositorio en github dando click a este enlace.
A lo mejor te parecerá que lejos de organizar mejor el código, hemos escrito demasiadas líneas en un mismo archivo, y en efecto, tienes razón, es por eso que Rust nos permite separar nuestro módulos en distintos archivos, de esta forma tendremos archivos muchos más sostenibles, sin embargo, es necesario conocer estos conceptos de módulos para poder trabajarlos bien, en nuestro siguiente post haremos otro ejemplo, pero ahora separando nuestro código en pequeños archivos (módulos) mucho mas fáciles de darle mantenimiento.
Recuerda que siempre puedes leer la primera parte de esta miniserie de organización de código con Rust acá:
Organizar Código En Rust - Paquetes y Librerías
Si este post te ha sido de utilidad compártelo con tus amigos y en tus redes sociales, también no olvides dejar tu comentario sobre lo que te ha gustado o no te ha gustado de esta publicación y aquellos temas que te gustaría aprender 😃.
println!("Hasta la próxima!");