How to accept argument ```"Option<String>" and "Option<&str>"```

I want to create a method which accepts "Option<String>" and "Option<&str>".
I've tried it with:

fn foo<T: AsRef<str>>(bar: Option<T>) {
  let local_bar = bar.map(|x| x.into()).unwrap_or_else(|| "default".to_string());
  ...
}

But this fails with

the trait bound `std::string::String: From<&T>` is not satisfied
required for `&T` to implement `Into<std::string::String>`

You have specified T: AsRef<str>, but called into(), not as_ref(). It looks like you want to require T: Into<String> instead.

4 Likes

Or:

fn foo<T: AsRef<str>>(bar: Option<T>) {
    let local_bar = bar
        .as_ref()
        .map(T::as_ref)
        .unwrap_or("default")
        .to_owned();
}
6 Likes

Note that the Into approach will avoid cloning[1] the passed in String in the case of Some(string). Assuming getting a String into local_bar is indeed the goal.


  1. and then presumably dropping ↩ī¸Ž

2 Likes

If you always need a String -- which from the example it looks like you do -- then just make the caller pass you a string.

It's really not worth the inference and compile-time performance costs, IMHO, if you're just going to force it to be an allocated String anyway.

(Things like &[AsRef<str>] can have their place, as can Into<Cow<str>>, but if you're going to force something into being a full String anyway, just take one.)

5 Likes