Menu
Coddy logo textTech

Métodos genéricos

Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 25 de 61.

Una estructura genérica puede contener cualquier tipo, pero no es muy útil sin métodos para interactuar con sus datos. Para definir métodos para una estructura genérica, necesitas una sintaxis especial en el bloque impl.

La clave es declarar el parámetro genérico en el propio impl:

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

Observa el impl<T> antes de Wrapper<T>. Esto le indica a Rust que T es un parámetro de tipo genérico para todo el bloque de implementación. Sin esta declaración, Rust buscaría un tipo concreto llamado T y no lograría encontrarlo.

El método get devuelve &T—una referencia a cualquier tipo que contenga el envoltorio. Esto funciona independientemente de si T es un entero, una cadena o cualquier otro tipo:

let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };

println!("{}", num_wrapper.get());  // 100
println!("{}", text_wrapper.get()); // Rust

La misma definición de método funciona para ambos, porque el genérico T se adapta a cada tipo concreto en tiempo de compilación.

challenge icon

Desafío

Fácil

¡Vamos a extender tu contenedor genérico con métodos! Construirás una estructura Box (no confundir con el Box estándar de Rust) que puede contener cualquier tipo y proporciona métodos para interactuar con su contenido.

Organizarás tu código en dos archivos:

  • mybox.rs: Define una estructura genérica pública llamada MyBox<T> con un campo privado contents de tipo T. Implementa métodos para esta estructura:
    • Una función asociada new que crea un nuevo MyBox con el valor dado
    • Un método peek que devuelve una referencia al contenido (usando &self)
    • Un método replace que toma un nuevo valor y reemplaza el contenido actual (usando &mut self)
  • main.rs: Importa tu módulo y demuestra los métodos genéricos funcionando con diferentes tipos. Crearás cajas, observarás su contenido y reemplazarás valores para mostrar los métodos en acción.

Recuerda la sintaxis clave para implementar métodos en una estructura genérica: necesitas impl<T> antes de MyBox<T> para indicarle a Rust que T es un parámetro genérico para todo el bloque de implementación.

En tu archivo principal, demuestra tu MyBox de la siguiente manera:

  1. Creando una caja con un entero (primera entrada, analizada como i32)
  2. Observando su contenido e imprimiendo el valor
  3. Reemplazando el contenido con un nuevo entero (segunda entrada, analizada como i32)
  4. Observando de nuevo para mostrar el valor actualizado
  5. Creando una segunda caja con una cadena (tercera entrada)
  6. Observando el contenido de la caja de cadena

Tu salida debe seguir este formato:

Integer box contains: {value}
After replace: {value}
String box contains: {value}

Por ejemplo, con las entradas 10, 25 y Rust:

Integer box contains: 10
After replace: 25
String box contains: Rust

Recibirás tres entradas: un entero inicial, un entero de reemplazo y un valor de cadena.

Hoja de referencia

Para definir métodos para una estructura genérica, declare el parámetro genérico en el bloque impl:

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

La sintaxis impl<T> le indica a Rust que T es un parámetro de tipo genérico para todo el bloque de implementación. Sin esto, Rust buscaría un tipo concreto llamado T.

Los métodos pueden devolver referencias al tipo genérico (&T), lo cual funciona para cualquier tipo concreto:

let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };

println!("{}", num_wrapper.get());  // 100
println!("{}", text_wrapper.get()); // Rust

Pruébalo tú mismo

mod mybox;

use mybox::MyBox;

fn main() {
    // Leer entradas
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let initial_int: i32 = input1.trim().parse().expect("Invalid integer");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let string_value = input3.trim().to_string();

    // TODO: Crear un MyBox con el entero inicial
    
    // TODO: Observar su contenido e imprimir: "Integer box contains: {value}"
    
    // TODO: Reemplazar el contenido con el entero de reemplazo
    
    // TODO: Observar de nuevo e imprimir: "After replace: {value}"
    
    // TODO: Crear un segundo MyBox con el valor de cadena
    
    // TODO: Observar la caja de cadena e imprimir: "String box contains: {value}"
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming