From e Into
Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 57 de 61.
Converter entre tipos é uma tarefa comum em Rust. A trait From fornece uma maneira padronizada de definir como um tipo pode ser criado a partir de outro. Quando você implementa From, você recebe a trait Into automaticamente de graça.
Para implementar From, você define como construir seu tipo a partir de outro tipo:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Agora você pode converter usando a função from ou o método into:
let distance = Kilometers(5.0);
// Usando From explicitamente
let m1 = Meters::from(distance);
// Usando Into (funciona porque From está implementado)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
O método into() exige uma anotação de tipo, já que o Rust precisa saber para qual tipo você está convertendo. Este padrão é especialmente útil quando você tem structs auxiliares que precisam ser convertidas em seus tipos principais — como converter dados de configuração em um objeto inicializado ou transformar uma entrada bruta em uma estrutura validada.
Desafio
FácilVamos construir um sistema de conversão de temperatura usando a trait From! Você criará dois tipos de temperatura—Celsius e Fahrenheit—e implementará conversões entre eles usando as traits de conversão padrão do Rust.
Você organizará seu código em dois arquivos:
temperature.rs: Defina duas structs newtype públicas—CelsiuseFahrenheit—ambas envolvendo umf64. Implemente a traitFrompara converterCelsiusemFahrenheitusando a fórmula:fahrenheit = celsius × 1.8 + 32.0. Adicione também um métodovaluea cada struct que retorna of64interno.main.rs: Importe seu módulo de temperatura e demonstre ambas as abordagens de conversão. Crie um valorCelsiusa partir da entrada fornecida e, em seguida, converta-o paraFahrenheitusandoFahrenheit::from(). Crie outro valorCelsiuse converta-o usando o método.into(). Imprima ambos os resultados.
A fórmula de conversão de Celsius para Fahrenheit é: multiplicar por 1.8 e somar 32. Lembre-se de que implementar From<Celsius> for Fahrenheit automaticamente fornece a trait Into<Fahrenheit> para Celsius gratuitamente!
Sua saída deve exibir ambas as conversões neste formato:
From: {celsius1}C = {fahrenheit1}F
Into: {celsius2}C = {fahrenheit2}FPor exemplo, com as entradas 0 e 100:
From: 0C = 32F
Into: 100C = 212FE com as entradas 25 e -40:
From: 25C = 77F
Into: -40C = -40FVocê receberá duas entradas: o primeiro valor Celsius (analise como f64) e o segundo valor Celsius (analise como f64).
Folha de consulta
A trait From fornece uma maneira padronizada de converter entre tipos. Quando você implementa From, você ganha automaticamente a trait Into de graça.
Para implementar From, defina como construir seu tipo a partir de outro tipo:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Você pode converter usando tanto a função from quanto o método into:
let distance = Kilometers(5.0);
// Using From explicitly
let m1 = Meters::from(distance);
// Using Into (requires type annotation)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
O método into() requer uma anotação de tipo para que o Rust saiba para qual tipo você está convertendo.
Experimente você mesmo
mod temperature;
use temperature::{Celsius, Fahrenheit};
fn main() {
// Ler a 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: Criar um valor Celsius a partir de celsius1
// TODO: Convertê-lo para Fahrenheit usando Fahrenheit::from()
// TODO: Criar outro valor Celsius a partir de celsius2
// TODO: Convertê-lo para Fahrenheit usando .into()
// TODO: Imprimir os resultados no formato:
// From: {celsius1}C = {fahrenheit1}F
// Into: {celsius2}C = {fahrenheit2}F
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Métodos e Comportamento
Introdução a Blocos de ImplementaçãoO Parâmetro SelfMétodos MutáveisFunções AssociadasMúltiplos Blocos de ImplementaçãoEncadeamento de MétodosRecapitulação - Ações de Retângulo4Projeto: Pet Virtual
Definindo o PetAlimentando o Pet7Traits Padrão
A Trait DebugA Trait DisplayClone e CopyTraits de IgualdadeRecapitulação - Ponto Imprimível10Projeto: Sistema de Documentos
A Trait DrawComponente de Texto2Encapsulamento e Módulos
Fundamentos de MódulosA Palavra-chave PublicCampos PrivadosGettersSettersRecapitulação - Cofre Seguro5Genéricos
Structs GenéricasMétodos GenéricosMúltiplos Tipos GenéricosFunções GenéricasRecapitulação - Ponto de Coordenada8Traits como Restrições
Sintaxe de Restrições de TraitRestrições MúltiplasA Cláusula WhereRetornando Tipos com TraitsRecapitulação - Impressora Genérica11Padrões de Projeto em Rust
Padrão NewtypeComposiçãoA Trait DropFrom e IntoRecapitulação - Mock de Smart Pointer3Enums Avançados
Enums com DadosMétodos em EnumsCorrespondência de Variantes de DadosO Enum Option RevisitadoRecapitulação - Enum Shape6Definição de Traits
O que é uma Trait?Implementando TraitsImplementações PadrãoSobrescrevendo PadrõesTraits com ParâmetrosRecapitulação - Media Player