4

Considering the following code:

let s = String::from("hello");
let mut r = String::new();

for c in s.chars() {
    r.push(c);
}

As chars is the method of &str, why can String call it? I suppose it has something to do with the coercion, but I don't fully understand this implicit conversion.

chenzhongpu
  • 6,193
  • 8
  • 41
  • 79
  • 1
    The exact explanation is in the [String documentation](https://doc.rust-lang.org/stable/std/string/struct.String.html#deref). – edwardw Sep 20 '19 at 07:44
  • @edwardw I know that it can convert `&String` to `&str`, but here it does not get the reference of `s`. – chenzhongpu Sep 20 '19 at 07:46
  • 2
    @chenzhongpu "When looking up a method call, the receiver may be automatically dereferenced or borrowed in order to call a method." (https://doc.rust-lang.org/reference/expressions/method-call-expr.html) – Denys Séguret Sep 20 '19 at 07:49
  • got it @DenysSéguret – chenzhongpu Sep 20 '19 at 07:51
  • 1
    See also the longer Deref coercion explanation in the book: https://doc.rust-lang.org/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods – Jussi Kukkonen Sep 20 '19 at 07:52
  • 1
    Does [What are Rust's exact auto-dereferencing rules?](https://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules) answer your question? – trent Sep 20 '19 at 12:11
  • @trentclt No, in this case, it is caused by both auto-reference (in the first step) and coercion (in the second step) – chenzhongpu Sep 20 '19 at 13:26

1 Answers1

2

This is actually covered in this question: What are Rust's exact auto-dereferencing rules?. There is a lot going on in that answer, so I will try to apply it to your question.

To quote huon's answer:

The core of the algorithm is:

  • For each "dereference step" U (that is, set U = T and then U = *T, ...)
    1. if there's a method bar where the receiver type (the type of self in the method) matches U exactly , use it (a "by value method")
    2. otherwise, add one auto-ref (take & or &mut of the receiver), and, if some method's receiver matches &U, use it (an "autorefd method")

The key is in the "dereference steps": U = *T means let u = Deref::deref(t);, where u: U, t: T. We keep doing that until something can't be dereferenced any more.

Following that algorithm for the call to s.chars() from your code:

  1. First dereference step (no deref):
    1. Can you call String::chars(s)? No.
    2. What about &String or &mut String? No.
  2. Second dereference step: <String as Deref>::Target = str, so we are looking for methods of str. let c: str = *s (assuming this DST type was allowed);
    1. Can you call str::chars(c)? No.
    2. Can you call str::chars(&c)? Yes!
Peter Hall
  • 53,120
  • 14
  • 139
  • 204