The reason for that is simple though: &String converts to &str, but not the other way around... so you should always use &str so that your code works with either, and notice that literal strings are &str.
I think Rust has lots of warts, but I don't see this as one of them (at least it's something you get irritated at only once, but then never have problems with).
I’m barely familiar with rust and forgot about this aspect, if I ever knew it.
Seems pretty sensible though. String is dynamic data on the heap that you own and can modify. str is some data somewhere that you can’t modify.
C has this distinction as well. Of course, in typical C fashion, the distinction isn’t expressed in the type system in any way. Instead, you just have to know that this char* is something you own and can modify and that char* just a reference to some data.
Higher level languages typically unify these ideas and handle the details for you, but that’s not rust’s niche.
>String is dynamic data on the heap that you own and can modify. str is some data somewhere that you can’t modify.
This is not the definition. You can modify both. Being able to modify something depends on whether you can do something with a &mut reference to it, and both &mut String and &mut str provide methods for modifying them.
The difference between the two types is just that String owns its allocation while str doesn't. So modifying a String is allowed to change its bytes as well as add and remove bytes, the latter because the String owns its allocation. Modifying a str only allows changing its bytes.