1

According to Rust Lang Programming Book, we know that:

The &self is actually short for self: &Self

However, from the example below (fn get_name), we wrote self: &Self, but self is not a reference but the object itself according to the error message. Why isn't self a reference in this case? What is the ampersand for in &Self then?

Example: a simple struct with method that returns a person's name

struct Person {
    name: String
}

impl Person {
    fn new(name: &str) -> Person {
        Person {
            name: name.to_string()
        }
    }

    fn get_name(self: &Self) -> &String {
        self.name // Error: expected `&std::string::String`, found struct `std::string::String`
    }
}
Jack Lien
  • 105
  • 6
  • 1
    Are you sure it's complaining about `self` and not `self.name`? – MisterMiyagi Jun 03 '22 at 07:26
  • 2
    `self` is a reference but `self.name` is not. You need to either return `&self.name` or change the return type to `String` and return `self.name.clone()`. – matias Jun 03 '22 at 07:28

1 Answers1

5

Because of automatic dereferencing.

C has the . and -> operators, where . is applied to values and -> to pointers. In C, x->y is exactly equivalent to (*x).y.

Rust has . but not ->, so to make the syntax friendly, . will usually automatically dereference when the compiler cannot find the member requested. In this case, &Person doesn't have a name attribute (since references can't have attributes), so the compiler tries again with a dereference ((*self).name) and it finds the attribute this time, on Person.

Since *self has type Person, (*self).name has type String. To fix the problem, you take a reference to the string by doing &self.name, which means the same thing as &((*self).name) (extra parens added for clarity).

To directly address your question:

... self is not a reference but the object itself according to the error message. Why isn't self a reference in this case?

The error message only refers to the String attribute and doesn't really give you any information about self at all. self is indeed a reference. If you throw this in your impl Person:

fn test(&self) { self }

Then the compiler will tell you what self is (because it doesn't match the implied () return type):

error[E0308]: mismatched types
  --> src/lib.rs:12:18
   |
12 | fn test(&self) { self }
   |                - ^^^^ expected `()`, found `&Person`
   |                |
   |                expected `()` because of default return type

Note that you will see the same compiler error if you say fn get_name(&self). This error isn't caused by the self: &Self syntax; it is indeed equivalent to &self.

cdhowie
  • 158,093
  • 24
  • 286
  • 300