Conversão segura de números em Rust: guia completo para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que a conversão de números em Rust não é brincadeira?

\n

Você já escreveu código em Python e fez tranquilamente int_var = 3.14 e depois float_var = int_var? Em Python isso funciona porque os tipos são dinâmicos. Mas em Rust, como um relojoeiro rigoroso, cada engrenagem deve ter seu tamanho certo. E se você tentar encaixar um u8 (0–255) em um u16 — é uma coisa, mas se for o contrário — pode ocorrer um "silencioso" truncamento de dados ou pânico.

\n

No Stack Overflow, a pergunta «How do I convert between numeric types safely and idiomatically?» acumulou milhares de visualizações. E não é por acaso: iniciantes frequentemente se perdem entre as, From e TryFrom. Neste artigo, vamos organizar todas as formas de conversão de números em Rust, explicar quando usar cada uma e mostrar exemplos que você pode aplicar imediatamente.

\n\n

1. Casting simples com as: rápido, mas perigoso

\n

A forma mais simples é o operador as. Ele funciona, mas com armadilhas.

\n
let big: u32 = 300;\nlet small: u8 = big as u8; // 300 não cabe em u8!\nprintln!("{}", small); // Saída: 44 (300 mod 256)\n
\n

O que aconteceu? Rust simplesmente pegou os 8 bits menos significativos do número 300 (0b1_0010_1100) e descartou o restante, deixando 0b0010_1100 = 44. Isso é chamado de truncamento (truncation). Para u8, isso pode ser uma surpresa.

\n

as é seguro apenas ao expandir o tipo (por exemplo, u8 → u16), quando o valor cabe com certeza. Para redução, é uma bomba-relógio.

\n

Quando usar as? Apenas quando você tem absoluta certeza de que o valor não ultrapassará os limites do tipo de destino. Por exemplo, ao trabalhar com máscaras de bits ou protocolos de baixo nível.

\n\n

2. Forma idiomática: as traits From e Into

\n

Rust é uma linguagem onde os erros devem ser explícitos. Por isso, a biblioteca padrão fornece as traits From e Into para conversão segura, que nunca falha.

\n

A regra é simples: se a conversão é sempre bem-sucedida (sem perda de dados), a trait é implementada. Por exemplo:

\n
let small: u8 = 42;\nlet big: u16 = small.into(); // Into chama From automaticamente\n// ou\nlet big: u16 = u16::from(small);\nprintln!("{}", big); // 42\n
\n

Atenção: From é implementado apenas para pares onde a conversão é garantidamente segura. Por exemplo, u8 → u16, i32 → f64, bool → i32. Mas u16 → u8 — não, porque pode haver estouro.

\n

Tente compilar este código:

\n
let big: u16 = 256;\nlet small: u8 = big.into(); // Erro de compilação!\n
\n

O compilador dirá: "the trait `From` is not implemented for `u8`". Isso é segurança — você não pode perder dados acidentalmente.

\n\n

3. Quando a conversão pode falhar: TryFrom e TryInto

\n

E se quisermos tentar converter u16 para u8, mas com verificação? Para isso, temos TryFrom e TryInto. Eles retornam um Result, que precisa ser tratado.

\n
use std::convert::TryFrom;\n\nlet big: u16 = 255;\nmatch u8::try_from(big) {\n    Ok(small) => println!("Sucesso: {}", small),\n    Err(e) => println!("Erro: {}", e),\n}\n// Saída: Sucesso: 255\n\nlet big: u16 = 256;\nmatch u8::try_from(big) {\n    Ok(small) => println!("Sucesso: {}", small),\n    Err(e) => println!("Erro: {}", e),\n}\n// Saída: Erro: TryFromIntError(())\n
\n

Isso é Rust idiomático: você trata explicitamente o possível erro. Pode usar unwrap() se tiver 100% de certeza, mas é melhor usar match.

Blogs

Book Recommendations