Use the ToString trait for simple conversions or format! for formatted output, as both are idiomatic and efficient in Rust. For performance-critical paths where you want to avoid heap allocation, consider using itoa for integers or ryu for floats to write directly into a pre-allocated buffer.
The most common approach is calling .to_string() on any type that implements Display. This works for integers, floats, and other standard types.
let number = 42;
let s = number.to_string();
assert_eq!(s, "42");
let float = 3.14;
let f_str = float.to_string();
assert_eq!(f_str, "3.14");
If you need to format the number (e.g., padding, specific decimal places) or convert multiple values at once, the format! macro is the standard tool. It returns a String and uses the same formatting syntax as println!.
let number = 5;
let padded = format!("{:05}", number); // "00005"
let with_unit = format!("The value is {}", number); // "The value is 5"
For high-performance scenarios where you are converting many numbers and want to avoid the overhead of allocating a new String every time, use the itoa crate for integers. It allows you to write the string representation directly into an existing Vec<u8> or a pre-allocated buffer.
// Add `itoa = "1"` to Cargo.toml
use itoa::Buffer;
let number = 12345;
let mut buf = Buffer::new();
let s = buf.format(number); // Returns &str, no allocation
assert_eq!(s, "12345");
Similarly, ryu provides the same zero-allocation capability for floating-point numbers. These crates are significantly faster than to_string() in tight loops because they reuse the buffer instead of allocating on the heap for every conversion. Choose to_string() or format! for readability and simplicity in most application code, and switch to itoa/ryu only when profiling indicates string conversion is a bottleneck.