TypeOwned alloc?AcceptsUse when
&strNostring slices onlyyou only read, no conversion needed
impl AsRef<str>No&str, String, Cow<str>read-only, zero-cost generic
impl Into<String>Yes, on call&str, Stringyou need to store/own it
impl ToStringYes, alwaysanything with Displayavoid — always allocates
Cow<'a, str>Sometimesborrowed or ownedyou want to delay allocation
StringYesString onlyexplicit, just take ownership

Practical rules:

  • Just reading → &str or impl AsRef<str>
  • Need to own/store → impl Into<String> (call .into() inside)
  • Avoid impl ToString — it always allocates, use impl Display if you need formatting
  • Cow<str> is niche — useful when you sometimes need to mutate/own and sometimes don’t

Most common correct pattern:

// read only
fn foo(s: impl AsRef<str>) {
    let s = s.as_ref();
}
 
// store it
fn foo(s: impl Into<String>) {
    let s = s.into();
}