192. impl Into<String> — Take Owned or Borrowed Without an Extra Allocation
Bite 191 said: if you only read the argument, take &str. But what if you need to store it? Taking &str and calling .to_owned() always allocates — even when the caller handed you a String it was about to throw away. impl Into<String> fixes that.
The hidden re-allocation
When a function keeps the value, the “take &str” rule turns into a trap:
| |
A literal caller has to allocate eventually — fair enough. But look what happens when the caller already owns a String:
| |
The caller had an owned buffer it no longer needed, and we ignored it.
Accept anything that becomes a String
Take impl Into<String>. A String moves in with zero copying; a &str allocates exactly once — never more:
| |
Same call site for both, and the owned case is now free. The conversion happens lazily at the boundary, exactly once, and only when it must.
When you only read: impl AsRef
If you don’t store the value but still want to accept more than deref coercion allows (String, &str, Box<str>, Cow<str>, …), reach for impl AsRef<str>:
| |
as_ref() is a cheap borrow — no allocation — and the generic accepts every string-like type without forcing the caller to convert first.
The rule of thumb
If the function stores the string, take impl Into<String> so an owned argument moves in for free. If it only reads but you want maximum flexibility, take impl AsRef<str>. Plain &str (bite 191) is still the right default for simple read-only functions — these two just cover the cases it can’t.