Vec::retain_mut¶
Level: reference · for working programmers
One line: retain, with a predicate that can also change the element.
Stable since 1.61.0.
Same single pass and same order as retain; the predicate takes &mut T instead of &T, so it can filter and edit in one traversal.
The alternative is two passes — for x in v.iter_mut() { … } then v.retain(…) — which is clearer when the two jobs are unrelated and wasteful when they are the same job.
The closure runs on every element, including the ones it then drops, so any mutation it performs happens to elements that are about to be discarded. Usually harmless; occasionally the bug.
Because the closure is FnMut, it can carry state — a running total, a budget, a counter — which is how "keep elements until the total exceeds N" becomes one call.
Stable since 1.61.0.
Example¶
vec_retain_mut.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
// Same pass as retain, but the predicate gets &mut T — so it can filter
// and edit in one traversal.
let mut v = vec![1, 2, 3, 4, 5];
v.retain_mut(|n| { *n *= 10; *n < 40 });
println!("{v:?}");
// Note what that means: the elements that get dropped were mutated first.
// The closure runs on every element, keep or not.
let mut touched = vec![];
let mut v = vec![1, 2, 3];
v.retain_mut(|n| { touched.push(*n); *n > 1 });
println!("predicate saw {touched:?}, kept {v:?}");
// Trimming and filtering a list of strings in one pass.
let mut lines = vec![
String::from(" alpha "),
String::from(" "),
String::from(" beta"),
];
lines.retain_mut(|s| { *s = s.trim().to_string(); !s.is_empty() });
println!("{lines:?}");
// Without retain_mut this is two passes (or a fold, or an index loop).
let mut lines = vec![String::from(" a "), String::from(" ")];
for s in lines.iter_mut() { *s = s.trim().to_string(); }
lines.retain(|s| !s.is_empty());
println!("the two-pass version: {lines:?}");
// A running state in the closure: keep every element whose running total
// is still under a budget, and record what it cost.
let mut spent = 0;
let mut costs = vec![3, 4, 10, 2, 5];
costs.retain_mut(|c| { if spent + *c <= 9 { spent += *c; true } else { false } });
println!("kept {costs:?} spending {spent}");
}
Verified output of vec_retain_mut.rs — regenerated by tools/run_examples.py, never hand-typed.
[10, 20, 30]
predicate saw [1, 2, 3], kept [2, 3]
["alpha", "beta"]
the two-pass version: ["a"]
kept [3, 4, 2] spending 9
See also¶
Vec::retain— when the predicate only needs to readVec::extract_if— the same&mutpredicate, yielding what it removesslice::iter_mut↗ — mutating without filtering