Implementación de Traits
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 30 de 61.
Ahora que sabes cómo definir un trait, veamos cómo hacer que un struct cumpla ese contrato. Implementar un trait conecta el requisito abstracto con el comportamiento concreto.
La sintaxis utiliza impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
El bloque impl Speak for Dog le dice a Rust que Dog está implementando el trait Speak. En el interior, proporcionas el cuerpo del método real—aquí es donde defines cómo habla un perro.
El poder de los traits queda claro cuando múltiples tipos implementan el mismo:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
Tanto Dog como Cat ahora comparten la capacidad Speak, pero cada uno proporciona su propia implementación única. Puedes llamar a .speak() en cualquier tipo:
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex dice: ¡Guau!
println!("{}", cat.speak()); // Whiskers dice: ¡Miau!
Esta es la base del polimorfismo en Rust—diferentes tipos, misma interfaz, comportamientos únicos.
Desafío
Fácil¡Demos vida a los traits implementándolos para diferentes tipos! Crearás un trait Describable y lo implementarás para dos structs diferentes, cada uno proporcionando su propia descripción única.
Organizarás tu código en tres archivos:
describable.rs: Define un trait públicoDescribablecon un métododescribe(&self) -> String.items.rs: Crea dos structs públicos que implementen tu trait:Bookcon un campo públicotitle(String)Moviecon un campo públiconame(String)
Describablecon su propio formato de descripción único.main.rs: Une tus módulos, crea instancias de ambos structs y llama a sus métodosdescribepara mostrar cómo el mismo trait produce diferentes salidas para diferentes tipos.
Tu Book debe describirse a sí mismo como Book: {title} y tu Movie debe describirse a sí mismo como Film: {name}. ¡Observa cómo cada tipo cumple con el mismo contrato pero con su propio comportamiento!
En tu archivo principal, crea un libro y una película utilizando las dos entradas proporcionadas, luego imprime sus descripciones en líneas separadas.
Tu salida debe seguir este formato:
Book: {title}
Film: {name}Por ejemplo, con las entradas 1984 e Inception:
Book: 1984
Film: InceptionRecibirás dos entradas: el título de un libro y el nombre de una película.
Hoja de referencia
Para implementar un trait para un struct, utiliza la sintaxis impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Múltiples tipos pueden implementar el mismo trait con diferentes comportamientos:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex says: Woof!
println!("{}", cat.speak()); // Whiskers says: Meow!
Esto permite el polimorfismo en Rust: diferentes tipos que comparten la misma interfaz con implementaciones únicas.
Pruébalo tú mismo
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// Leer entradas
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: Crear una instancia de Book con el título
// TODO: Crear una instancia de Movie con el nombre
// TODO: Imprimir la descripción del libro
// TODO: Imprimir la descripción de la película
}
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