String::with_capacity¶
Level: reference · for working programmers
One line: An empty String with room for at least n bytes reserved up front — one allocation instead of a doubling sequence.
Stable since 1.0.0.
The string is still empty; only the buffer is bought. len() is 0 and capacity() is at least n.
Growing a String by pushing reallocates on a doubling schedule, and each reallocation copies everything written so far. Building a 1 KB string from new() costs several allocations and several copies; from with_capacity(1024) it costs one and none.
The capacity is in bytes, not characters. Sizing a buffer for 100 characters of non-ASCII text needs up to 400 bytes.
Reserving is not a promise the string will not grow — pushing past n reallocates normally. And over-reserving wastes memory until shrink_to_fit gives it back, so the honest use is a size you can actually estimate: a known record length, a file's byte count, input.len() for a transformation that roughly preserves size.
Example¶
string_with_capacity.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
let s = String::with_capacity(32);
println!("len {} capacity {}", s.len(), s.capacity());
// No reallocation while it fits.
let mut planned = String::with_capacity(32);
for word in ["alpha ", "beta ", "gamma"] {
planned.push_str(word);
println!("len {:>2} capacity {:>2}", planned.len(), planned.capacity());
}
// Growing from nothing walks a doubling sequence instead.
let mut grown = String::new();
for word in ["alpha ", "beta ", "gamma"] {
grown.push_str(word);
println!("len {:>2} capacity {:>2} (from new)", grown.len(), grown.capacity());
}
println!("equal contents: {}", planned == grown);
// Bytes, not characters.
let wide = "é".repeat(4);
println!("4 chars need {} bytes", wide.len());
// Sizing from the input is the honest estimate.
let input = "the quick brown fox";
let mut upper = String::with_capacity(input.len());
upper.push_str(&input.to_ascii_uppercase());
println!("{} / {}", upper.len(), upper.capacity());
}
Verified output of string_with_capacity.rs — regenerated by tools/run_examples.py, never hand-typed.
len 0 capacity 32
len 6 capacity 32
len 11 capacity 32
len 16 capacity 32
len 6 capacity 8 (from new)
len 11 capacity 16 (from new)
len 16 capacity 16 (from new)
equal contents: true
4 chars need 8 bytes
19 / 19
See also¶
String::new— when the size is unknownString::reserve— the same idea on a string that already existsString::capacity— what this setsString::shrink_to_fit— giving back what you over-reserved
String::with_capacity in the standard library ↗
Po polsku¶
with_capacity kupuje bufor, a nie treść: łańcuch znaków jest nadal pusty (len 0), zmienia się wyłącznie pojemność (capacity). Zysk jest czysto wydajnościowy — rosnący String realokuje się według podwajania i za każdym razem przepisuje wszystko, co już w nim jest. W przykładzie oba przebiegi stoją obok siebie: startując od new() pojemność idzie 8 → 16 → 16, a przy with_capacity(32) przez cały czas zostaje 32 i nie ma ani jednej realokacji.
Dla polskiego czytelnika kluczowe jest jedno zdanie: pojemność liczy się w bajtach, nie w znakach. with_capacity(100) zamawia 100 bajtów, a nie miejsce na 100 znaków — każda polska litera z diakrytykiem zajmuje w UTF-8 dwa bajty, emoji albo znak CJK cztery, więc pole na nazwisko pełne ą, ę i ł potrzebuje mniej więcej dwa razy więcej miejsca, niż podpowiada intuicja; stąd cztery znaki é z przykładu to 8 bajtów. Rezerwacja nie jest też obietnicą, że łańcuch nie urośnie: zapis powyżej n realokuje najzwyczajniej w świecie, a rezerwacja z nadmiarem marnuje pamięć aż do shrink_to_fit. Uczciwe oszacowanie to takie, które naprawdę znasz — długość rekordu, rozmiar pliku w bajtach albo input.len() dla przekształcenia mniej więcej zachowującego długość.
Szukaj po polsku: pojemność łańcucha znaków w bajtach · realokacja i podwajanie bufora · rust String with_capacity · rust string capacity bytes not chars