Conversão de tipos em Rust
O Rust não converte um tipo em outro automaticamente para você: se você misturar um i32 e um f64 na mesma expressão, o código não compila. A conversão precisa ser explícita. Isso é de propósito, porque conversões silenciosas são uma fonte comum de bugs em outras linguagens.
Convertendo entre tipos numéricos com as
Seção intitulada “Convertendo entre tipos numéricos com as”Use a palavra-chave as para converter (fazer um cast de) um tipo numérico em outro:
fn main() { let x: i32 = 10; let y: f64 = x as f64; // i32 -> f64
println!("{y}");}Isso importa mais do que parece. Experimente dividir dois inteiros sem converter e você vai ter uma divisão inteira, em vez do resultado decimal que provavelmente queria:
fn main() { let a = 10; let b = 3;
println!("{}", a / b); // 3 (divisão inteira) println!("{}", a as f64 / b as f64); // 3.3333333333333335}Converter para um tipo menor pode perder dados
Seção intitulada “Converter para um tipo menor pode perder dados”Converter de um tipo maior para um menor (como de i32 para u8) não dá erro: o valor simplesmente é cortado, o que pode gerar um resultado surpreendente:
fn main() { let big: i32 = 300; let small = big as u8; // u8 só guarda de 0 a 255 println!("{small}"); // 44, e não 300: o valor deu a volta}Convertendo floats, caracteres e booleanos
Seção intitulada “Convertendo floats, caracteres e booleanos”O as funciona com mais alguns tipos além dos números inteiros. Cada um tem uma regra que vale a pena conhecer:
fn main() { println!("{}", 3.99_f64 as i32); // 3: as casas decimais são cortadas println!("{}", -3.99_f64 as i32); // -3: corta em direção ao zero, não para baixo println!("{}", 3.99_f64.round() as i32); // 4: arredonde antes, se é isso que você quer println!("{}", 300.0_f64 as u8); // 255: grande demais, então para no máximo println!("{}", -5.0_f64 as u8); // 0: pequeno demais, então para no mínimo println!("{}", 'A' as u32); // 65: o número de código de um char println!("{}", 97_u8 as char); // a: e de volta println!("{}", true as i32); // 1 (false seria 0)}Saída:
3-34255065a1O que levar daqui:
- De float para inteiro, tudo depois do ponto decimal é jogado fora. Não há arredondamento. Chame
.round()antes se quiser o número inteiro mais próximo. - Floats fora da faixa são limitados ao valor mais próximo que cabe (
300.0vira255em umu8). Isso é diferente dos inteiros, que dão a volta (300virou44lá em cima). - Caracteres têm um número por trás (o code point Unicode deles).
'A' as u32dá65. Só umu8pode ser convertido direto de volta parachar; para números maiores você usariachar::from_u32, porque nem todo número é um caractere válido. - Booleanos viram
1ou0. O caminho inverso não funciona:1 as boolnão compila. Use uma comparação comon != 0no lugar.
Convertendo strings em números
Seção intitulada “Convertendo strings em números”A conversão com as só funciona entre tipos numéricos. Para transformar um texto em número (por exemplo, algo que o usuário digitou), use .parse():
fn main() { let text = "42"; let number: i32 = text.parse().expect("não é um número válido");
println!("{}", number + 8);}Saída:
50O .parse() pode falhar (e se o texto nem for um número?), por isso ele retorna um Result em vez do número diretamente. Ainda não vimos o Result. Por enquanto, .expect("mensagem") é um jeito simples de dizer “se der errado, pare o programa com esta mensagem”. Você vai ver o jeito certo de tratar isso na página Result.
Números em strings
Seção intitulada “Números em strings”O caminho inverso é mais simples: quase todo tipo pode virar uma String com .to_string():
fn main() { let number = 42; let text = number.to_string(); println!("{}", text + "!");}Prática
Seção intitulada “Prática”1. Nota média
Seção intitulada “1. Nota média”Guarde três notas de prova como valores i32: 7, 8 e 10. Imprima a soma e depois a média com duas casas decimais. Dica: se você dividir dois inteiros, vai obter 8, e não 8.33, então converta a soma para f64 antes. {:.2} imprime duas casas decimais.
Ver solução
fn main() { let a: i32 = 7; let b: i32 = 8; let c: i32 = 10;
let sum = a + b + c; let average = sum as f64 / 3.0; // 25.0 / 3.0, e não 25 / 3
println!("soma: {sum}"); println!("média: {:.2}", average);}Saída:
soma: 25média: 8.332. Preço a partir de um texto
Seção intitulada “2. Preço a partir de um texto”Uma loja passa o preço como texto, "4.50", e a quantidade como um i32, 3. Transforme o texto em f64, multiplique pela quantidade e imprima Total: 13.5. Dica: você precisa das duas ferramentas desta página: .parse() para o texto e as f64 para a quantidade.
Ver solução
fn main() { let price_text = "4.50"; let quantity: i32 = 3;
let price: f64 = price_text.parse().expect("não é um preço válido"); let total = price * quantity as f64; // f64 * f64
println!("Total: {total}");}Saída:
Total: 13.5Sem o as f64, o Rust se recusaria a multiplicar um f64 por um i32, porque ele nunca mistura tipos numéricos por você. Repare também que o .parse() espera um ponto como separador decimal: "4,50" não seria um número válido.
- O Rust nunca converte tipos automaticamente: você sempre faz a conversão de forma explícita.
- Use
aspara converter entre tipos numéricos:x as f64,x as u8. - Converter para um tipo menor corta o valor em silêncio, sem dar erro, então tome cuidado.
- De float para inteiro, as casas decimais são cortadas (use
.round()antes para arredondar).charebooltambém podem ser convertidos em números. - Use
.parse()para transformar texto em número e.to_string()para fazer o contrário.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. O que acontece quando você divide dois inteiros, como 10 / 3, em Rust sem converter?
2. O que acontece quando você converte 300_i32 com as u8?
3. O que o .parse() retorna ao converter uma string em número, já que a conversão pode falhar?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- Casting — Rust by Example (em inglês): muitas conversões com
asque você pode rodar, com comentários sobre exatamente o que cada uma produz. - Type cast expressions — The Rust Reference (em inglês): a tabela completa de quais conversões são permitidas e a regra precisa de cada uma.
- To and from Strings — Rust by Example (em inglês):
.to_string()e.parse()com um pouco mais de profundidade. TryFrom— documentação da biblioteca padrão (em inglês): a conversão verificada (u8::try_from(...)) para usar quando um valor talvez não caiba.- Numeric Types — The Rust Reference (em inglês): o tamanho e a faixa de valores de cada tipo inteiro e de ponto flutuante.