28

I want to write a single function, that accepts a &str, a String and a borrowed &String. I've written the following 2 functions:

fn accept_str_and_ref_string(value: &str) {
    println!("value: {}", value);
}

fn accept_str_and_string<S: Into<String>>(value: S) {
    let string_value: String = value.into();
    println!("string_value: {}", string_value);
}

fn main() {
    let str_foo = "foo";
    let string_foo = String::from("foo");

    accept_str_and_ref_string(str_foo);
    accept_str_and_ref_string(&string_foo);

    accept_str_and_string(str_foo);
    accept_str_and_string(string_foo);
}

Is it possible to implement one function so that I can do this:

accept_all_strings(str_foo);
accept_all_strings(&string_foo);
accept_all_strings(string_foo);
Shepmaster
  • 326,504
  • 69
  • 892
  • 1,159
Ringo Leese
  • 515
  • 4
  • 6
  • 1
    It looks like since Rust 1.35.0 the `Into` variant also works for [`&String`](https://doc.rust-lang.org/std/string/struct.String.html#impl-From%3C%26%27_%20String%3E). – Matthias Jul 07 '19 at 17:57
  • Yes, you're right, I've testet it with the current 1.36 version of Rust. – Ringo Leese Jul 08 '19 at 17:36

1 Answers1

39

You can use the AsRef<str> trait:

// will accept any object that implements AsRef<str>
fn print<S: AsRef<str>>(stringlike: S) {
    // call as_ref() to get a &str
    let str_ref = stringlike.as_ref();

    println!("got: {:?}", str_ref)
}

fn main() {
    let a: &str = "str";
    let b: String = String::from("String");
    let c: &String = &b;

    print(a);
    print(c);
    print(b);
}

The print function will support any type that implements AsRef<str>, which includes &str, String and &String.

Frxstrem
  • 34,562
  • 9
  • 73
  • 106
  • @trentcl A `String` will not be copied, the ownership of it will be passed to the method unless you are using a reference. – Frxstrem Mar 09 '19 at 16:05
  • 1
    My mistake, my brain mashed up the body of the OP's example with the signature of yours. – trent Mar 09 '19 at 16:32
  • 1
    What if the function eventually needs an owned string rather than a reference? – malthe Dec 30 '19 at 10:06
  • 6
    @malthe Personally I typically just use `stringlike.as_ref().to_string()`, as I like having the same signature regardless of whether I need an owned or borrowed string. I think that might be a bit inefficient with arguments that are already owned strings, so if you want to avoid that you can use other traits, like `S: Into`. – Frxstrem Dec 30 '19 at 13:23