Skip to content

String::retain

String methods · Strings

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.

pub fn retain<F>(&mut self, f: F)
where
    F: FnMut(char) -> bool,

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.

"prgrmmng"
"héllowörld"
"abcd"
"abc" capacity 32
"123"

See also

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