rustreferencerust-cargodereference

Why does dereferencing a String (not &String) work in Rust?


In the following code, in calculate_length function we are sending String not &String, yet dereferencing works. I expected to get error something: type String cannot be dereferenced

But the code compiles and run without any error/warnings.

fn main() {
    let  x = String::from("hello world");
    let z = calculate_length(x);

    println!("{:}", z);
}

fn calculate_length(s: String) -> usize {
    (*s).len()
}

Playgorund Code here


Solution

  • First, String implements Deref, which means you can use the dereference operator * on it. However, you're partially correct that s can't be dereferenced. If you write let x = *s;, it won't compile because this would copy String's target type, str. And str can't be copied since it doesn't implement Copy due to being unsized.

    But while *s can't be a value, it is a valid place expression, which means you can do some things to it, like assign to it, make it a reference &*s, or call methods on it.

    Methods are very flexible and can add references and dereferences in order to find a suitable function with the specified name. In (*s).len(), the method adds & in order to call str::len, which would look like str::len(&*s) expanded out. The added reference keeps the str from needing to be copied. Then the dereference *s is expanded to become str::len(&*Deref::deref(&s)).