String::push¶
Level: reference · for working programmers
One line: Appends one char, encoding it as 1–4 UTF-8 bytes — so len() can grow by more than one.
Stable since 1.0.0.
The argument is a char, not a &str, so it takes single quotes: s.push('!'). Appending text uses push_str, and s.push("!") is a type error people meet early.
len() grows by c.len_utf8(), which is 1 for ASCII and up to 4 otherwise. So a loop that pushes n characters does not produce a string of length n.
Amortized O(1): the buffer doubles when it fills, so a run of pushes is cheap on average even though individual ones reallocate.
Building a String character by character is idiomatic, but chars().map(..).collect::<String>() usually reads better and sizes the buffer more sensibly.
Example¶
string_push.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
let mut s = String::from("hi");
s.push('!');
println!("{s:?}");
// A char is 1..=4 bytes, so len grows by more than one.
let mut wide = String::new();
for c in ['a', 'é', '👋'] {
wide.push(c);
println!("pushed {c:?} -> len {} (grew by {})", wide.len(), c.len_utf8());
}
// push takes a char; push_str takes text.
let mut t = String::new();
t.push('a');
t.push_str("bc");
println!("{t:?}");
// Growth doubles, so a run of pushes is cheap on average.
let mut grown = String::new();
let mut capacity = grown.capacity();
for i in 1..=9 {
grown.push('x');
if grown.capacity() != capacity {
capacity = grown.capacity();
println!("push {i} reallocated: len {} capacity {capacity}", grown.len());
}
}
// collect is usually the better spelling.
let shouted: String = "hi".chars().map(|c| c.to_ascii_uppercase()).collect();
println!("{shouted:?}");
}
Verified output of string_push.rs — regenerated by tools/run_examples.py, never hand-typed.
"hi!"
pushed 'a' -> len 1 (grew by 1)
pushed 'é' -> len 3 (grew by 2)
pushed '👋' -> len 7 (grew by 4)
"abc"
push 1 reallocated: len 1 capacity 8
push 9 reallocated: len 9 capacity 16
"HI"
See also¶
String::push_str— appending text rather than one characterString::pop— the inverseString::insert— putting a character anywhere but the endstr::chars— the iterator that feeds a push loop
String::push in the standard library ↗
Po polsku¶
Najczęstsza wywrotka na tej metodzie jest składniowa, nie pojęciowa: push przyjmuje pojedynczy znak (char), więc pisze się s.push('!') w apostrofach — s.push("!") w cudzysłowie to E0308, mismatched types, bo od tekstu jest osobne push_str. Druga rzecz to arytmetyka długości: len() rośnie o c.len_utf8(), czyli o 1 dla ASCII, ale o 2 dla é, ą czy ż i o 4 dla emoji, co strona pokazuje ciągiem len 1, len 3, len 7 po trzech dołożeniach — pętla dokładająca n znaków nie daje więc łańcucha o długości n. Koszt jest zamortyzowany O(1), bo bufor podwaja się dopiero, gdy się zapełni (stąd push 1 reallocated ... capacity 8 i push 9 ... capacity 16), ale jeśli budujesz łańcuch znak po znaku z iteratora, czytelniejsze i rozsądniej dobierające rozmiar bufora bywa chars().map(..).collect::<String>().
Szukaj po polsku: znak a łańcuch znaków · apostrof czy cudzysłów · rust push char vs push_str · rust E0308 expected char found &str · rust collect into String