String::push_str() / push() / +
To append to a Rust String, you can use push_str() (append a string slice), push() (append a single character), the + operator, or the format!() macro. Each method handles ownership differently.
Syntax
let mut s = String::from("Hello");
// Appends a &str to the end (ownership is not moved).
s.push_str(", World"); // s = "Hello, World"
// Appends a single char to the end.
s.push('!'); // s = "Hello, World!"
// + operator: consumes ownership of the left operand and concatenates.
let s1 = String::from("Hello");
let s2 = String::from(", World");
let s3 = s1 + &s2; // s1's ownership is moved. s2 is borrowed.
// s1 can no longer be used here. s3 = "Hello, World"
// format! macro: concatenates while keeping ownership of all variables.
let s4 = format!("{}-{}-{}", "Hello", "World", "Rust");
Method List
| Method / Syntax | Description |
|---|---|
| s.push_str(str) | Appends a &str to the end. Ownership is not moved. |
| s.push(char) | Appends a single char to the end. |
| s1 + &s2 | Concatenates s1 (ownership moved) and s2 (borrowed). |
| format!("{}{}", s1, s2) | Concatenates multiple strings while retaining ownership of all. |
| s.extend(iter) | Appends elements from an iterator to the string. |
| s.repeat(n) | Returns a new String with the content repeated n times. |
| s.insert(idx, char) | Inserts a char at the given byte index idx. |
| s.insert_str(idx, str) | Inserts a &str at the given byte index idx. |
Sample Code
fn main() {
// push_str: appends a string (the variable must be mutable).
let mut s = String::from("Hello");
s.push_str(", Rust");
s.push('!');
println!("push_str + push: {}", s);
// Concatenation with the + operator (watch out for ownership).
let s1 = String::from("Hello");
let s2 = String::from(", World");
let s3 = s1 + &s2; // s1's ownership is consumed.
// println!("{}", s1); // ← Error! s1 can no longer be used.
println!("+ operator: {}", s3);
// Chaining multiple + calls becomes hard to read.
let s4 = String::from("tic");
let s5 = String::from("tac");
let s6 = String::from("toe");
// s4 + &s5 + &s6 is hard to read, so format! is recommended.
let s7 = format!("{}-{}-{}", s4, s5, s6); // Ownership is not moved.
println!("format!: {}", s7);
println!("s4: {}", s4); // With format!, ownership is retained.
// extend: appends from an iterator.
let mut s = String::from("Hello");
s.extend([',', ' ', 'R', 'u', 's', 't']);
println!("extend: {}", s);
// repeat: repeats the string.
let repeated = "ha".repeat(3);
println!("repeat: {}", repeated); // hahaha
// insert / insert_str: inserts in the middle.
let mut s = String::from("Hello!");
s.insert(5, ','); // Inserts a comma at index 5.
s.insert_str(6, " World"); // Inserts a string at index 6.
println!("insert: {}", s); // Hello, World!
// Common pattern: building a string incrementally.
let parts = ["apple", "banana", "cherry"];
let mut result = String::new();
for (i, part) in parts.iter().enumerate() {
if i > 0 {
result.push_str(", ");
}
result.push_str(part);
}
println!("Result: {}", result);
}
Notes
When choosing how to concatenate strings, use format!() for readable multi-string joins. Use push_str() when building a string incrementally in a loop. If performance matters, pre-allocate memory with String::with_capacity() to avoid repeated reallocations.
The + operator consumes ownership of the left-hand String. If you need to use the left-hand variable afterward, use format!() instead.
For ways to create a String, see String::from() / to_string().
If you find any errors or copyright issues, please contact us.