Introdução: por que no Rust não se pode simplesmente somar um número com uma string?
\n\nSe você veio do Python ou JavaScript, está acostumado a escrever algo como str(42) ou 42 + "". No Rust, esse truque não funciona. O compilador pergunta estritamente: "Que tipo você quer obter? Integer? String? Decida-se!"
A pergunta "How do I convert from an integer to a string?" é uma das mais populares no Stack Overflow na seção Rust. Milhares de desenvolvedores quebram a cabeça tentando entender por que seu código não compila quando tentam escrever:
\n\nlet number = 42;\nlet text = number; // Erro: expected `&str`, found `i32`\n\nHoje vamos explorar os bastidores dessa conversão. Você aprenderá não apenas como fazer, mas também como funciona no nível de traits, alocações e até mesmo assembly. Vamos lá!
\n\nA maneira mais simples: o método to_string()
\n\nNo Rust, como na maioria das linguagens modernas, os tipos inteiros possuem o método to_string(). Ele parece enganosamente simples:
fn main() {\n let num: i32 = 255;\n let s: String = num.to_string();\n println!("{}", s); // Exibe: "255"\n}\n\nIsso funciona para todos os tipos inteiros: i8, u32, i64, usize, etc.
O que acontece nos bastidores?
\n\nO método to_string() não é mágica do compilador. Ele é implementado através da trait Display. Na biblioteca padrão do Rust, existe a implementação:
// Versão simplificada da biblioteca padrão\nimpl<T: fmt::Display> ToString for T {\n #[inline]\n fn to_string(&self) -> String {\n use fmt::Write;\n let mut buf = String::new();\n // Aqui é chamado o método fmt() da trait Display\n let _ = buf.write_fmt(format_args!("{}", self));\n buf.shrink_to_fit(); // Otimização de memória\n buf\n }\n}\n\nPonto-chave: to_string() cria uma nova String no heap. Cada chamada é uma alocação de memória. Para centenas de milhares de conversões, isso pode se tornar um gargalo de desempenho.
Alternativa: a macro format!
\n\nA segunda maneira popular é a macro format!. Ela funciona como println!, mas em vez de exibir no console, retorna uma String:
fn main() {\n let num = 1024;\n let s = format!("{}", num);\n println!("Comprimento da string: {}", s.len()); // 4\n}\n\nA diferença entre to_string() e format! é mínima. to_string() internamente chama format_args! e write_fmt. Na prática, é a mesma coisa. A escolha é uma questão de estilo e legibilidade.
Quando usar format!?
\n- \n
- Quando precisar inserir um número no meio de uma string:
format!("Número: {}", num)\n - Quando o formato for complexo (hexadecimal, com separadores):
format!("{:#x}", 255)→ "0xff" \n - Quando a expressividade do código for importante \n
Trait Display vs ToString: qual é mais rápido?
\n\nSe você está escrevendo uma biblioteca ou código de alto desempenho, use diretamente a trait Display através de write! em um buffer. Isso permite reutilizar a memória já alocada:
use std::fmt::Write;\n\nfn main() {\n let num = 42;\n let mut buffer = String::with_capacity(20); // Aloca memória antecipadamente\n\n // Escreve o número no buffer\n write!(buffer, "{}", num).unwrap();\n println!("{}", buffer); // "42"\n\n // Limpa e reutiliza\n buffer.clear();\n write!(buffer, "{}", 256).unwrap();\n println!("{}", buffer); // "256"\n}\n\nEssa abordagem proporciona um ganho de desempenho de até 2-3x em loops onde é necessário converter números em strings repetidamente, porque a alocação de memória ocorre