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()
}
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))
.