Introducción: ¿por qué en Rust no se puede simplemente sumar un número con una cadena?
\n\nSi vienes de Python o JavaScript, estás acostumbrado a escribir algo como str(42) o 42 + "". En Rust, ese truco no funciona. El compilador preguntará estrictamente: "¿Qué tipo quieres obtener? ¿Integer? ¿String? ¡Decídete!"
La pregunta "How do I convert from an integer to a string?" es una de las más populares en Stack Overflow en la sección de Rust. Miles de desarrolladores se rompen la cabeza preguntándose por qué su código no compila cuando intentan escribir:
\n\nlet number = 42;\nlet text = number; // Error: expected `&str`, found `i32`\n\nHoy exploraremos a fondo esta conversión. No solo aprenderás cómo hacerlo, sino también cómo funciona a nivel de traits, asignaciones de memoria e incluso ensamblador. ¡Allá vamos!
\n\nLa forma más sencilla: el método to_string()
\n\nEn Rust, como en la mayoría de los lenguajes modernos, los tipos enteros tienen el método to_string(). Se ve engañosamente simple:
fn main() {\n let num: i32 = 255;\n let s: String = num.to_string();\n println!("{}", s); // Muestra: "255"\n}\n\nEsto funciona para todos los tipos enteros: i8, u32, i64, usize, etc.
¿Qué sucede internamente?
\n\nEl método to_string() no es magia del compilador. Se implementa a través del trait Display. En la biblioteca estándar de Rust existe esta implementación:
// Versión simplificada de la biblioteca estándar\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 // Aquí se llama al método fmt() del trait Display\n let _ = buf.write_fmt(format_args!("{}", self));\n buf.shrink_to_fit(); // Optimización de memoria\n buf\n }\n}\n\nPunto clave: to_string() crea un nuevo String en el heap. Cada llamada implica una asignación de memoria. Para cientos de miles de conversiones, esto puede convertirse en un cuello de botella de rendimiento.
Alternativa: la macro format!
\n\nLa segunda forma popular es la macro format!. Funciona como println!, pero en lugar de mostrar en consola, devuelve un String:
fn main() {\n let num = 1024;\n let s = format!("{}", num);\n println!("Longitud de la cadena: {}", s.len()); // 4\n}\n\nLa diferencia entre to_string() y format! es mínima. to_string() internamente llama a format_args! y write_fmt. En esencia, es lo mismo. La elección es cuestión de estilo y legibilidad.
¿Cuándo usar format!?
\n- \n
- Cuando necesitas insertar un número en medio de una cadena:
format!("Número: {}", num)\n - Cuando el formato es complejo (hexadecimal, con separadores):
format!("{:#x}", 255)→ "0xff" \n - Cuando la expresividad del código es importante \n
Trait Display vs ToString: ¿cuál es más rápido?
\n\nSi escribes una biblioteca o código de alto rendimiento, usa directamente el trait Display a través de write! en un buffer. Esto permite reutilizar la memoria ya asignada:
use std::fmt::Write;\n\nfn main() {\n let num = 42;\n let mut buffer = String::with_capacity(20); // Asignamos memoria de antemano\n\n // Escribimos el número en el buffer\n write!(buffer, "{}", num).unwrap();\n println!("{}", buffer); // "42"\n\n // Limpiamos y reutilizamos\n buffer.clear();\n write!(buffer, "{}", 256).unwrap();\n println!("{}", buffer); // "256"\n}\n\nEste enfoque proporciona hasta 2-3 veces más rendimiento en bucles donde se necesita convertir números a cadenas repetidamente, porque la asignación de memoria ocu