String slice as parameter - syntax question


#1

Hi there,
I’m completely new to Rust and currently working my way through “The Book”.
While reading the Chapter on Strings and the invocation of push_str, I got confused about the syntax when invoking a function that takes a string slice as parameter.

Say we have a function fn foo(s: &str) and define a variable let x = "Hello World";.
Are these function calls all equivalent to each other? If so, why?

foo(x); // 1
foo(&x); // 2
foo(&x[..]); // 3

If x already is of type &str, why does 2 work?


#2

Yes, they’re basically equivalent

This is where the “deref coercion” kicks in. It’s described in Deref coerctions chapter of The Book. Basically, Rust will strip layers of & from the type, if you passed a “more referenced” type and a “less referenced” type is expected. Like here, when you coerce &&str&str. (Note that this this coercion won’t strip the last &, so eg. no &FooFoo, as it’s not always possible (eg. when you neither can’t Clone nor Copy a Foo)). Deref coercions also works on some “smart pointer” types (which implement Deref trait), so you can also convert &String&str, &Vec<T>&[T] or &Rc<T>&T.

The third example is using a string slice syntax. x[..] desugars to *x.index(..) aka. *x.index(RangeFull). The index returns a &str here, but compiler inserts a *–dereference, so you need to reference it again to come back to str. So foo(&x[..])foo(&*x.index(RangeFull)).


#3

Thank you for this quick and detailed reply. I’ll have a look at the appropriate chapter in The Book. :slight_smile: