I know I can make passing string values as arguments easier by using Into<String>, which makes it possible to pass both &str and String and will convert &str to String if needed.
fn test<T>(value: T)
where T: Into<String> {
}
test("foo");
test("bar".to_string());
On the other hand I also know that you can convert a value into an Option, which makes it possible to pass either the value or None:
impl From<String> for Vec<String> {
^^^^^------------^^^^^-----------
| | |
| | `std::vec::Vec` is not defined in the current crate
| `std::string::String` is not defined in the current crate
impl doesn't use only types from inside the current crate
@asymmetrikon: Thanks for your example, I played with it and finally even was able to make it possible to convert both &str and String into Vec<String>. It had no real purpose, but I just wanted to understand.
@rrbutani: I tried to understand why you had to specify the types as you did in the last three scenarios, and when I was playing with both your and asymmetrikon's solution, I merged both solutions together and was able to accept &str, String, Some(&str) and Some(String), but I was not able to accept None as it was ambiguous, so I had to specify either <&str> or <String> as type, which is ugly and defeats the purpose.
You should be able to get it to work more generally: EDIT: Actually this doesn't help with the ambiguity, but it might be a better option anyway, as it doesn't always allocate a String, depending on what you need.
use std::borrow::Borrow;
fn test<A, B>(val: A)
where A: Into<Option<B>>, B: Borrow<str>,
{
let val: Option<B> = val.into();
match val {
Some(b) => println!("{:?}", b.borrow()),
None => println!("None"),
}
}
fn main() {
test("hello");
test("hallo".to_string());
test::<_, &str>(Some("hi"));
test::<_, String>(Some("👋".to_string()));
test::<_, String>(None);
}
From here, you can always call to_string, on the borrowed result if you really need String: Just convert everything to Option<&str> and then do with that what you wish.