Hacker News new | ask | show | jobs
by LtdJorge 241 days ago
Because to_string allocates. And if a function requires a String (owned), it cannot accept a str reference (borrowed), it would defeat the purpose of the strong type system. String is moved, while str is passed by reference.

There is the exception of Deref. If the function requires type A, and you pass it type B, which Derefs into type A, the compiler will Deref it for you. But that is zero cost and panic free, whereas allocating (and copying) an owned type from a reference isn't. In Rust you have to be explicit.

Anyway, using String in function signatures is most often not the best choice. If you will internally be required to use a String, it's better to ask for a type "impl Into<String>", you'd call into() inside your function. And in the most common case, where you require a &str or can convert to your type from it, the best choice is an "impl AsRef<str>" and you can call as_ref() on it to get a str reference, which you can wrap in a Box, Rc, Arc, String, or your custom type, or pass it directly to other functions. All of those, Box<str>, Rc<str>, etc implement both traits.

Using impl Trait, you avoid having to declare generic parameters.

1 comments

If only one could construct a macro to solve the boilerplate of AsRef<str> etc ;)
To me, there’s not much difference between:

  fn foo(name: &str) {}
and*:

  fn foo(name: impl AsRef<str>) {}