Traits con parámetros
Parte de la sección Object Oriented Programming 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 al igual que los métodos regulares; 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 un struct 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 diferentes tipos realicen las mismas operaciones a su propia manera; tal vez un LoggingCalc podría imprimir cada operación antes de devolver el resultado.
Desafío
Fácil¡Vamos a construir un conjunto de herramientas de manipulación de cadenas donde diferentes procesadores puedan transformar texto a su manera! Crearás un trait TextProcessor con métodos que aceptan parámetros y luego 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 dado un número especificado de vecestruncate(&self, text: &str, max_len: usize) -> String— acorta el texto a la longitud máxima especificada
processors.rs: Crea dos structs públicos que implementen tu trait:SimpleProcessor— un struct de unidad 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— un struct de unidad que repite el texto con " * " entre repeticiones (por ejemplo, "Hi" repetido 3 veces se convierte en "Hi * Hi * Hi") y trunca añadiendo "..." si el texto fue acortado (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 utilices.
En tu archivo principal, crea ambos procesadores y utiliza las entradas para probarlos. Recibirás tres entradas: una cadena de texto, un recuento 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 con el mismo contrato TextProcessor, pero cada uno transforma el texto a su 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 a procesar, el número de repeticiones (analizar como u32) y la longitud máxima para el truncamiento (analizar como usize).
Hoja de referencia
Los métodos de los traits pueden aceptar parámetros adicionales más allá de &self:
trait Calculator {
fn add(&self, a: i32, b: i32) -> i32;
fn multiply(&self, a: i32, b: i32) -> i32;
}
Implementando un trait con parámetros:
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
}
}
Usando métodos de trait 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.
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: Usar los procesadores para transformar el texto e imprimir los resultados
// Imprimir 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 Object Oriented Programming
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 multimedia