261. String::retain — Delete Characters In Place, No New Allocation
Stripping characters with replace("-", "") builds a brand-new String just to throw characters away. retain deletes them in the buffer you already own.
The trap
This morning’s bite (260) covered replacen — but both replace and replacen always return a fresh String, even when the “replacement” is deleting. Same story with the iterator route:
| |
If you’re cleaning strings in a loop, that’s one allocation per string, per pass — for data you already had in a perfectly good buffer.
The fix
String::retain keeps every char the closure approves and shifts the rest out, in place, in one O(n) pass:
| |
No new allocation, and the capacity stays put — ready for push_str later. It reads as intent, too: “keep digits” instead of “replace non-digits with nothing”.
One caveat
The closure sees chars in order, exactly once, and retain keeps what returns true — it’s a keep-list, not a kill-list. To delete matches, negate:
| |
Vec<T> and VecDeque<T> have the same method, so the pattern transfers. When you need to substitute text, replace/replacen earn their allocation — but when you’re only deleting, retain does it where the string already lives.