Traits con parámetros
Parte de la sección Programación Orientada a Objetos del Journey de Rust de Coddy. Lección 33 de 61.
Hasta ahora, nuestros métodos de trait solo han tomado &self como parámetro. Pero los métodos de trait pueden aceptar parámetros adicionales, igual que los métodos normales. Esto los hace mucho más útiles para operaciones del mundo real.
Al definir un trait, puedes incluir cualquier parámetro que necesites en las firmas de los métodos:
trait Calculator {
fn add(&self, a: i32, b: i32) -> i32;
fn multiply(&self, a: i32, b: i32) -> i32;
}
Este trait Calculator requiere dos métodos, cada uno de los cuales acepta dos enteros además de &self. Cualquier tipo que implemente este trait debe proporcionar ambas operaciones con estas firmas exactas.
Así es como una estructura podría implementarlo:
struct BasicCalc;
impl Calculator for BasicCalc {
fn add(&self, a: i32, b: i32) -> i32 {
a + b
}
fn multiply(&self, a: i32, b: i32) -> i32 {
a * b
}
}
Ahora puedes usar estos métodos con argumentos:
let calc = BasicCalc;
println!("{}", calc.add(5, 3)); // 8
println!("{}", calc.multiply(4, 7)); // 28
El trait define qué parámetros acepta cada método, mientras que la implementación define cómo se utilizan esos parámetros. Esto permite que distintos tipos realicen las mismas operaciones a su manera: quizá un LoggingCalc podría imprimir cada operación antes de devolver el resultado.
Desafío
Fácil¡Construyamos un conjunto de herramientas para manipular cadenas donde diferentes procesadores puedan transformar el texto a su manera! Crearás un trait TextProcessor con métodos que aceptan parámetros y después lo implementarás para dos tipos de procesadores diferentes.
Organizarás tu código en tres archivos:
processor.rs: Define un trait públicoTextProcessorcon dos métodos que aceptan parámetros:repeat(&self, text: &str, times: u32) -> String: repite el texto indicado un número específico de vecestruncate(&self, text: &str, max_len: usize) -> String: acorta el texto hasta la longitud máxima indicada
processors.rs: Crea dos estructuras públicas que implementen tu trait:SimpleProcessor: una estructura unitaria que repite el texto con espacios entre cada repetición (por ejemplo, "Hi" repetido 3 veces se convierte en "Hi Hi Hi") y trunca simplemente cortando en la longitud máximaFancyProcessor: una estructura unitaria que repite el texto con " * " entre las repeticiones (por ejemplo, "Hi" repetido 3 veces se convierte en "Hi * Hi * Hi") y trunca añadiendo "..." si el texto se acortó (solo si el texto original era más largo que max_len)
main.rs: Une tus módulos y demuestra cómo los mismos métodos del trait producen resultados diferentes según el procesador que uses.
En tu archivo principal, crea ambos procesadores y usa las entradas para probarlos. Recibirás tres entradas: una cadena de texto, un número de repeticiones y una longitud máxima.
Imprime cuatro líneas que muestren el comportamiento de cada procesador:
Simple repeat: {result}
Simple truncate: {result}
Fancy repeat: {result}
Fancy truncate: {result}Por ejemplo, con las entradas Hello, 3 y 4:
Simple repeat: Hello Hello Hello
Simple truncate: Hell
Fancy repeat: Hello * Hello * Hello
Fancy truncate: Hell...Observa cómo ambos procesadores cumplen el mismo contrato TextProcessor, pero cada uno transforma el texto de una manera única. El trait define qué parámetros aceptan los métodos, mientras que cada implementación decide cómo usarlos.
Recibirás tres entradas: el texto que se procesará, el número de repeticiones (analízalo como u32) y la longitud máxima para el truncamiento (analízala como usize).
Pruébalo tú mismo
mod processor;
mod processors;
use processor::TextProcessor;
use processors::{SimpleProcessor, FancyProcessor};
fn main() {
// Leer entradas
let mut text = String::new();
std::io::stdin().read_line(&mut text).expect("Failed to read line");
let text = text.trim();
let mut times_input = String::new();
std::io::stdin().read_line(&mut times_input).expect("Failed to read line");
let times: u32 = times_input.trim().parse().expect("Failed to parse times");
let mut max_len_input = String::new();
std::io::stdin().read_line(&mut max_len_input).expect("Failed to read line");
let max_len: usize = max_len_input.trim().parse().expect("Failed to parse max_len");
// Crear procesadores
let simple = SimpleProcessor;
let fancy = FancyProcessor;
// TODO: Usa los procesadores para transformar el texto e imprimir los resultados
// Imprime cuatro líneas:
// Simple repeat: {result}
// Simple truncate: {result}
// Fancy repeat: {result}
// Fancy truncate: {result}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Métodos y Comportamiento
Intro a Bloques de ImplementaciónEl Parámetro SelfMétodos MutablesFunciones AsociadasMúltiples Bloques de ImplementaciónEncadenamiento de MétodosResumen - Acciones de Rectángulo4Proyecto: Mascota virtual
Definir la mascotaAlimentar a la mascota7Traits estándar
El trait DebugEl trait DisplayClone y CopyTraits de igualdadResumen - Punto imprimible10Proyecto: Sistema de documentos
El Trait DrawComponente de texto2Encapsulamiento y módulos
Conceptos básicos de módulosLa palabra clave PublicCampos privadosGettersSettersRepaso - Casillero seguro5Genéricos
Estructuras genéricasMétodos genéricosMúltiples tipos genéricosFunciones genéricasResumen - Punto de coordenadas8Traits como límites
Sintaxis de límites de traitsLímites múltiplesLa cláusula whereRetornar tipos con traitsResumen: Impresora genérica11Patrones de diseño en Rust
Patrón NewtypeComposiciónEl Trait DropFrom e IntoResumen - Mock de Smart Pointer3Enums avanzados
Enums con datosMétodos en EnumsCoincidencia de variantes de datosEl Enum Option revisitadoResumen - Enum Shape6Definición de Traits
¿Qué es un Trait?Implementación de TraitsImplementaciones por defectoSobrescribir valores por defectoTraits con parámetrosResumen - Reproductor multimediaPractica por tu cuenta: Compilador de Rust online