Menu
CoddyTech

Múltiples tipos genéricos

Parte de la sección Programación Orientada a Objetos del Journey de Rust de Coddy. Lección 26 de 61.

A veces un único parámetro genérico no es suficiente. ¿Qué ocurre si necesitas una estructura que contenga dos valores y esos valores pueden ser de tipos diferentes? Rust te permite usar varios parámetros genéricos separándolos con comas.

Aquí tienes una estructura Pair que contiene dos valores de tipos potencialmente diferentes:

struct Pair<T, U> {
    first: T,
    second: U,
}

<T, U> declara dos parámetros de tipo independientes. T y U pueden ser del mismo tipo o completamente diferentes: depende de ti al crear una instancia:

let both_ints = Pair { first: 10, second: 20 };       // T=i32, U=i32
let mixed = Pair { first: "hello", second: 3.14 };    // T=&str, U=f64
let reversed = Pair { first: 100, second: "world" }; // T=i32, U=&str

Al implementar métodos, declaras todos los parámetros genéricos en el bloque impl:

impl<T, U> Pair<T, U> {
    fn get_first(&self) -> &T {
        &self.first
    }

    fn get_second(&self) -> &U {
        &self.second
    }
}

Este patrón es común cuando necesitas asociar dos piezas de datos relacionadas pero potencialmente diferentes, como un par key-value, coordenadas con diferentes tipos numéricos o un resultado emparejado con metadatos.

challenge icon

Desafío

Fácil

¡Construyamos un sistema de almacenamiento de clave-valor que demuestre el poder de múltiples tipos genéricos! Crearás una estructura KeyValue que puede emparejar dos tipos cualesquiera, perfecta para asociar etiquetas con datos, identificadores con objetos o cualquier otra combinación.

Organizarás tu código en dos archivos:

  • keyvalue.rs: Define una estructura genérica pública llamada KeyValue<K, V> con dos campos privados: key de tipo K y value de tipo V. Implementa métodos para trabajar con esta estructura:
    • Una función asociada new que crea un KeyValue a partir de una clave y un valor
    • Un método key que devuelve una referencia a la clave
    • Un método value que devuelve una referencia al valor
    • Un método set_value que reemplaza el valor actual por uno nuevo
  • main.rs: Incorpora tu módulo y demuestra cómo la misma definición de estructura funciona con diferentes combinaciones de tipos. Crearás pares de clave-valor con tipos mixtos para mostrar la flexibilidad de los múltiples tipos genéricos.

En tu archivo principal, crea y trabaja con los siguientes pares de clave-valor:

  1. Un par con una clave de tipo cadena y un valor entero (la primera entrada como clave, la segunda entrada analizada como i32 como valor)
  2. Imprime la clave y el valor
  3. Actualiza el valor a un nuevo entero (la tercera entrada analizada como i32)
  4. Imprime el valor actualizado
  5. Crea un segundo par con una clave entera y un valor de tipo cadena (la cuarta entrada analizada como i32 como clave, la quinta entrada como valor)
  6. Imprime la clave y el valor de este par

Tu salida debe seguir este formato:

Key: {key}, Value: {value}
Updated value: {value}
Key: {key}, Value: {value}

Por ejemplo, con las entradas name, 42, 100, 7 y lucky:

Key: name, Value: 42
Updated value: 100
Key: 7, Value: lucky

Observa cómo el primer par usa KeyValue<String, i32>, mientras que el segundo usa KeyValue<i32, String>: ¡la misma estructura, diferentes combinaciones de tipos!

Recibirás cinco entradas: una clave de tipo cadena, un valor entero, un entero de reemplazo, una clave entera y un valor de tipo cadena.

Pruébalo tú mismo

mod keyvalue;

use keyvalue::KeyValue;

fn main() {
    // Lee cinco entradas
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let string_key = input1.trim().to_string();

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

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

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

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

    // TODO: Crea un par KeyValue<String, i32> usando string_key e int_value

    // TODO: Imprime la clave y el valor en el formato: "Key: {key}, Value: {value}"

    // TODO: Actualiza el valor usando set_value con replacement_int

    // TODO: Print the updated value in format: "Updated value: {value}"

    // TODO: Crea un par KeyValue<i32, String> usando int_key y string_value

    // TODO: Imprime la clave y el valor de este par en el formato: "Key: {key}, Value: {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 Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Rust online