Search code examples
rustreferenceself

Rust: Why isn't "self" a reference when "self: &Self"?


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`
    }
}

Solution

  • 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.