String slice vs String type

What’s happening here is a coercion, in particular you can coerce

&T or &mut T to &U if T implements Deref<Target = U> .

And coercion can happen at coercion sites, in particular for:

Arguments for function calls
The value being coerced is the actual parameter, and it is coerced to the type of the formal parameter.

In the standard library the type String implements Deref with a Target = str ⟶ here.

This is why your code compiles even though you are passing a &String to a function expecting a &str.

I want to second and amend @kornel’s note that &String should be avoided, because it doesn’t give you any advantages over &str and also since a function expecting &str can just as well accept &String but not vice versa (so your functions are more general i.e. more useful when they take &str).