Use format! for one-off concatenation or String::push_str (or the + operator) when building strings in a loop. The format! macro is the most idiomatic way to combine multiple values into a new string, while push_str is more efficient for incremental construction since it avoids reallocating memory on every step.
For simple cases involving two strings, the + operator works but requires the left operand to be a String and the right to be a &str. If you are concatenating many strings in a loop, prefer a String buffer with push_str or push to prevent quadratic time complexity caused by repeated reallocations.
// Using format! for one-off concatenation (most common)
let s1 = "Hello";
let s2 = "World";
let combined = format!("{} {}", s1, s2); // Result: "Hello World"
// Using + operator (left must be String, right must be &str)
let greeting = String::from("Rust");
let message = greeting + " is great"; // Result: "Rust is great"
// Note: `greeting` is moved and no longer usable after this line
When building strings dynamically, such as in a loop, initialize a String with capacity_hint if possible and use push_str to append. This approach minimizes memory allocations.
let mut result = String::with_capacity(100); // Pre-allocate to avoid reallocations
for i in 0..5 {
result.push_str("item ");
result.push_str(&i.to_string());
result.push('\n');
}
// Result: "item 0\nitem 1\n...item 4\n"
Avoid using + inside loops because it creates a new String on every iteration, which is inefficient. Similarly, don't use format! inside tight loops if you can reuse a buffer. If you need to join a collection of strings with a separator, use the join method on an iterator, which is both readable and optimized.
let words = vec!["Rust", "is", "fast"];
let sentence = words.join(" "); // Result: "Rust is fast"
Choose format! for readability in simple cases, join for collections, and push_str with a pre-allocated buffer for performance-critical string building.