String::retain¶
Level: reference · for working programmers
One line: Keeps only the characters a predicate approves, in one linear in-place pass — the right way to filter a String.
Stable since 1.26.0.
The closure takes a char and returns true to keep it. Characters are visited in order, and the survivors are compacted toward the front, so it is O(n) with no allocation — where a remove loop would be O(n²) and would need the offsets recomputed after every deletion.
The predicate is FnMut, so it can carry state: keeping the first occurrence of each character, or dropping everything after a marker, both work.
The alternative is s.chars().filter(..).collect::<String>(), which allocates a new string. retain is the in-place version and keeps the existing capacity.
Example¶
string_retain.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
let mut s = String::from("programming");
s.retain(|c| !"aeiou".contains(c));
println!("{s:?}");
// Works on non-ASCII, because it visits chars rather than bytes.
let mut mixed = String::from("héllo wörld");
mixed.retain(|c| c.is_alphabetic());
println!("{mixed:?}");
// FnMut: the predicate can carry state.
let mut seen = String::new();
let mut dedup = String::from("aabbccdd");
dedup.retain(|c| if seen.contains(c) { false } else { seen.push(c); true });
println!("{dedup:?}");
// In place: the capacity survives.
let mut roomy = String::with_capacity(32);
roomy.push_str("a1b2c3");
roomy.retain(char::is_alphabetic);
println!("{roomy:?} capacity {}", roomy.capacity());
// The allocating alternative.
println!("{:?}", "a1b2c3".chars().filter(|c| c.is_numeric()).collect::<String>());
}
Verified output of string_retain.rs — regenerated by tools/run_examples.py, never hand-typed.
See also¶
String::remove— the O(n²) way to do the same thingString::drain— removing a range rather than by a rulestr::replace— substituting rather than deletingString::clear— removing everything
String::retain in the standard library ↗
Po polsku¶
Nazwa mówi, w którą stronę działa predykat: retain zachowuje znaki, dla których domknięcie (closure) zwróci true, więc filtr wyrzucający samogłoski trzeba zapisać z przeczeniem — |c| !"aeiou".contains(c). Dla polskiego tekstu najważniejsze jest to, że metoda ogląda znaki, a nie bajty, więc predykaty z rodziny is_alphabetic zostawią ó, ż i ł równie spokojnie jak é oraz ö w przykładzie ("héllowörld"); po is_ascii_alphabetic wszystkie polskie litery z ogonkami zniknęłyby bez słowa ostrzeżenia. Przebieg jest jeden, liniowy i w miejscu — ocalałe znaki ściskają się ku początkowi, a pojemność zostaje nienaruszona ("abc" capacity 32) — i tym retain bije pętlę po remove, kwadratową i wymagającą przeliczania przesunięć po każdym usunięciu. Predykat jest typu FnMut, więc wolno mu nieść stan: w przykładzie usuwa w ten sposób duplikaty ("aabbccdd" na "abcd"), a gdy oryginał ma zostać nietknięty, alternatywą jest alokujące chars().filter(..).collect::<String>().
Szukaj po polsku: filtrowanie znaków w miejscu · predykat zachowujący znaki · polskie znaki a funkcje ASCII · rust String retain · rust filter chars collect String