From e Into
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 57 de 61.
Convertir entre tipos es una tarea común en Rust. El trait From proporciona una forma estandarizada de definir cómo se puede crear un tipo a partir de otro. Cuando implementas From, obtienes el trait Into automáticamente de forma gratuita.
Para implementar From, defines cómo construir tu tipo a partir de otro tipo:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Ahora puedes realizar la conversión utilizando ya sea la función from o el método into:
let distance = Kilometers(5.0);
// Usando From explícitamente
let m1 = Meters::from(distance);
// Usando Into (funciona porque From está implementado)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
El método into() requiere una anotación de tipo ya que Rust necesita saber a qué tipo estás convirtiendo. Este patrón es especialmente útil cuando tienes estructuras auxiliares que necesitan ser convertidas a tus tipos principales—como convertir datos de configuración en un objeto inicializado, o transformar una entrada bruta en una estructura validada.
Desafío
Fácil¡Vamos a construir un sistema de conversión de temperatura utilizando el trait From! Crearás dos tipos de temperatura—Celsius y Fahrenheit—e implementarás conversiones entre ellos utilizando los traits de conversión estándar de Rust.
Organizarás tu código en dos archivos:
temperature.rs: Define dos structs newtype públicos—CelsiusyFahrenheit—ambos envolviendo unf64. Implementa el traitFrompara convertirCelsiusenFahrenheitusando la fórmula:fahrenheit = celsius × 1.8 + 32.0. También añade un métodovaluea cada struct que devuelva elf64interno.main.rs: Incorpora tu módulo de temperatura y demuestra ambos enfoques de conversión. Crea un valorCelsiusa partir de la entrada proporcionada, luego conviértelo aFahrenheitusandoFahrenheit::from(). Crea otro valorCelsiusy conviértelo usando el método.into(). Imprime ambos resultados.
La fórmula de conversión de Celsius a Fahrenheit es: multiplicar por 1.8 y sumar 32. ¡Recuerda que implementar From<Celsius> for Fahrenheit te otorga automáticamente el trait Into<Fahrenheit> en Celsius de forma gratuita!
Tu salida debe mostrar ambas conversiones en este formato:
From: {celsius1}C = {fahrenheit1}F
Into: {celsius2}C = {fahrenheit2}FPor ejemplo, con las entradas 0 y 100:
From: 0C = 32F
Into: 100C = 212FY con las entradas 25 y -40:
From: 25C = 77F
Into: -40C = -40FRecibirás dos entradas: el primer valor Celsius (analizado como f64) y el segundo valor Celsius (analizado como f64).
Hoja de referencia
El trait From proporciona una forma estandarizada de convertir entre tipos. Cuando implementas From, obtienes automáticamente el trait Into de forma gratuita.
Para implementar From, define cómo construir tu tipo a partir de otro tipo:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Puedes realizar la conversión utilizando la función from o el método into:
let distance = Kilometers(5.0);
// Usando From explícitamente
let m1 = Meters::from(distance);
// Usando Into (requiere anotación de tipo)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
El método into() requiere una anotación de tipo para que Rust sepa a qué tipo estás realizando la conversión.
Pruébalo tú mismo
mod temperature;
use temperature::{Celsius, Fahrenheit};
fn main() {
// Leer la entrada
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let celsius1: f64 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let celsius2: f64 = input2.trim().parse().expect("Invalid number");
// TODO: Crear un valor Celsius a partir de celsius1
// TODO: Convertirlo a Fahrenheit usando Fahrenheit::from()
// TODO: Crear otro valor Celsius a partir de celsius2
// TODO: Convertirlo a Fahrenheit usando .into()
// TODO: Imprimir los resultados en el formato:
// From: {celsius1}C = {fahrenheit1}F
// Into: {celsius2}C = {fahrenheit2}F
}
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