Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does &* combined together do in Rust?

Tags:

rust

I was reading through the book section about Strings 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?

like image 639
D. Ataro Avatar asked Dec 21 '16 22:12

D. Ataro


1 Answers

In short: the * triggers an explicit deref, which can be overloaded via ops::Deref.


More Detail

Look at this code:

let s = "hi".to_string();  // : String
let a = &s;

What's the type of a? It's simply &String! This shouldn't be very surprising, since we take the reference of a String. Ok, but what about this?

let s = "hi".to_string();  // : String
let b = &*s;   // equivalent to `&(*s)`

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:

impl Deref for String {
    type Target = str;
    fn deref(&self) -> &str { ... }
}

So, *s is actually *std::ops::Deref::deref(&s), in which the deref() function has the return type &str which is then dereferenced again. Thus, *s has the type str (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, the Deref-overload is used via automatic deref coercion. When the target type is fixed, the compiler will deref for you:

fn takes_string_slice(_: &str) {}

let s = "hi".to_string();  // : String
takes_string_slice(&s); // this works!
like image 55
Lukas Kalbertodt Avatar answered Oct 02 '22 13:10

Lukas Kalbertodt