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.
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 llamadaKeyValue<K, V>con dos campos privados:keyde tipoKyvaluede tipoV. Implementa métodos para trabajar con esta estructura:- Una función asociada
newque crea unKeyValuea partir de una clave y un valor - Un método
keyque devuelve una referencia a la clave - Un método
valueque devuelve una referencia al valor - Un método
set_valueque reemplaza el valor actual por uno nuevo
- Una función asociada
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:
- Un par con una clave de tipo cadena y un valor entero (la primera entrada como clave, la segunda entrada analizada como
i32como valor) - Imprime la clave y el valor
- Actualiza el valor a un nuevo entero (la tercera entrada analizada como
i32) - Imprime el valor actualizado
- Crea un segundo par con una clave entera y un valor de tipo cadena (la cuarta entrada analizada como
i32como clave, la quinta entrada como valor) - 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: luckyObserva 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}"
}
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