Conversão de integer para string em Rust: magia sem unwrap e macros

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 no Rust não se pode simplesmente somar um número com uma string?

\n\n

Se 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!"

\n\n

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\n
let number = 42;\nlet text = number; // Erro: expected `&str`, found `i32`
\n\n

Hoje 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\n

A maneira mais simples: o método to_string()

\n\n

No Rust, como na maioria das linguagens modernas, os tipos inteiros possuem o método to_string(). Ele parece enganosamente simples:

\n\n
fn main() {\n    let num: i32 = 255;\n    let s: String = num.to_string();\n    println!("{}", s); // Exibe: "255"\n}
\n\n

Isso funciona para todos os tipos inteiros: i8, u32, i64, usize, etc.

\n\n

O que acontece nos bastidores?

\n\n

O 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:

\n\n
// 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\n

Ponto-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.

\n\n

Alternativa: a macro format!

\n\n

A segunda maneira popular é a macro format!. Ela funciona como println!, mas em vez de exibir no console, retorna uma String:

\n\n
fn main() {\n    let num = 1024;\n    let s = format!("{}", num);\n    println!("Comprimento da string: {}", s.len()); // 4\n}
\n\n

A 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.

\n\n

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
\n\n

Trait Display vs ToString: qual é mais rápido?

\n\n

Se 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:

\n\n
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\n

Essa 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

Blogs

Book Recommendations