I was reading through the book section about String
s and found they were using &*
combined together to convert a piece of text. The following is what it says:
use std::net::TcpStream;
TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str.
let addr_string = "192.168.0.1:3000".to_string();
TcpStream::connect(&*addr_string); // Convert `addr_string` to &str.
In other words, they are saying they are converting a String
to a &str
. But why is that conversion done using both of the aforementioned signs? Should this not be done using some other method? Does not the &
mean we are taking its reference, then using the *
to dereference it?
In general,
&*
means to first dereference (*
) and then reference (&
) a value. In many cases, this would be silly, as we'd end up at the same thing.However, Rust has deref coercions. Combined with the
Deref
andDerefMut
traits, a type can dereference to a different type!This is useful for
String
s as that means that they can get all the methods fromstr
, it's useful forVec<T>
as it gains the methods from[T]
, and it's super useful for all the smart pointers, likeBox<T>
, which will have all the methods of the containedT
!Following the chain for
String
:No, your order of operations is backwards.
*
and&
associate to the right. In this example, dereferencing is first, then referencing.(from a comment)
Sometimes, this will do the same thing. See What are Rust's exact auto-dereferencing rules? for the full details, but yes, a
&String
can be passed to a function that requires a&str
. There are still times where you need to do this little dance by hand. The most common I can think of is:You'll note that we actually dereference twice:
Although this case can now be done with
name.as_ref().map(String::as_str);
In short: the
*
triggers an explicit deref, which can be overloaded viaops::Deref
.More Detail
Look at this code:
What's the type of
a
? It's simply&String
! This shouldn't be very surprising, since we take the reference of aString
. Ok, but what about this?What's the type of
b
? It's&str
! Wow, what happened?Note that
*s
is executed first. As most operators, the dereference operator*
is also overloadable and the usage of the operator can be considered syntax sugar for*std::ops::Deref::deref(&s)
(note that we recursively dereferencing here!).String
does overload this operator:So,
*s
is actually*std::ops::Deref::deref(&s)
, in which thederef()
function has the return type&str
which is then dereferenced again. Thus,*s
has the typestr
(note the lack of&
).Since
str
is unsized and not very handy on its own, we'd like to have a reference to it instead, namely&str
. We can do this by adding a&
in front of the expression! Tada, now we reached the type&str
!&*s
is rather the manual and explicit form. Often, theDeref
-overload is used via automatic deref coercion. When the target type is fixed, the compiler will deref for you: