190. Return Cow<str> — Allocate Only When You Actually Change Something
An escaping or normalizing function usually has nothing to do — the input is already clean. Returning String forces an allocation anyway. Return Cow<str> and the common path stays a borrow.
The wasteful version
A function that escapes HTML returns String, so every caller pays for an allocation — even the overwhelming majority whose input contains nothing to escape:
| |
"hello world" has no special characters, yet replace still walks the string three times and hands back a fresh String. In a template renderer or a parser running this over thousands of fields, that’s thousands of pointless heap allocations.
Borrow on the fast path
Cow<str> lets one return type be either a borrow or an owned String. Check first; only allocate when there’s real work:
| |
The clean input never touches the heap; the dirty input allocates once instead of three times:
| |
Callers don’t notice
Cow<str> derefs to &str, so anything that reads the result just works — no .unwrap(), no matching:
| |
And when a caller genuinely needs ownership, .into_owned() allocates only if it’s still borrowed:
| |
The rule: any function that might return its input unchanged — escaping, trimming, normalizing, path canonicalization — should return Cow<str>, not String. The signature tells the caller “I’ll borrow when I can,” and the body only reaches for the heap on the path that earns it.