user266003
user266003

Reputation:

What's the difference between self and Self?

I haven't come across Self in the documentation, only in the source code. The documentation only uses self.

Upvotes: 150

Views: 50770

Answers (4)

aura
aura

Reputation: 543

A bit late to this post, but I recently learned that Self can be used to refer static methods.

See the answer by anon80458984 here.

Also see the solution of rustlings excercises, where Self::try_from is used to call a static method.

Upvotes: 0

snnsnn
snnsnn

Reputation: 13718

Self refers to the current type that implements a trait, self on the other hand refers to the instance.

Having self as the first parameter is how rust defines methods. It is just a convention that converts a function into a method, much like in python. Functionally, self is analogous to this in JavaScript.

For those who don't know the difference between a function and a method, methods are functions that are attached to an instance and invoked via that instance.

Self is a generic type and that is why it is not allowed in any position that requires a concrete type. This is commonly referred to as being object safe in rust docs.

Self is also used in method definitions inside an impl block so that when you rename the type during a refactoring, you don't have to go through every method and fixed them.

In Rust, self is also used in module resolution which refers to the current module. Here, it imports the io module:

use std::io::{self, Read};

Upvotes: 21

Matthieu M.
Matthieu M.

Reputation: 300439

Self is the type of the current object. It may appear either in a trait or an impl, but appears most often in trait where it is a stand-in for whatever type will end up implementing the trait (which is unknown when defining the trait):

trait Clone {
    fn clone(&self) -> Self;
}

If I then implement Clone:

impl Clone for MyType {
    // I can use either the concrete type (known here)
    fn clone(&self) -> MyType;

    // Or I can use Self again, it's shorter after all!
    fn clone(&self) -> Self;
}

I could also use it in a regular impl if I am lazy (it's shorter!):

impl MySuperLongType {
    fn new(a: u32) -> Self { ... }
}

self is the name used in a trait or an impl for the first argument of a method. Using another name is possible, however there is a notable difference:

  • if using self, the function introduced is a method
  • if using any other name, the function introduced is an associated function

In Rust, there is no implicit this argument passed to a type's methods: you have to explicitly pass the "current object" as a method parameter. This would result in:

impl MyType {
    fn doit(this: &MyType, a: u32) { ... }
}

As we have seen, as a shorter form this could also be (still verbose):

impl MyType {
    fn doit(this: &Self, a: u32) { ... }
}

Which is actually what &self boils down to under the covers.

impl MyType {
    fn doit(&self, a: u32) { ... }
}

Thus the correspondence table:

self => self: Self
&self => self: &Self
&mut self => self: &mut Self

The way to invoke those functions change, however:

impl MyType {
    fn doit(&self, a: u32) {
        // ...
    }
    fn another(this: &Self, a: u32) {
        // ...
    }
}

fn main() {
    let m = MyType;

    // Both can be used as an associated function
    MyType::doit(&m, 1);
    MyType::another(&m, 2);

    // But only `doit` can be used in method position
    m.doit(3);     // OK: `m` is automatically borrowed
    m.another(4);  // ERROR: no method named `another`
}

Upvotes: 217

llogiq
llogiq

Reputation: 14541

self when used as first method argument, is a shorthand for self: Self. There are also &self, which is equivalent to self: &Self, and &mut self, which is equivalent to self: &mut Self.

Self in method arguments is syntactic sugar for the receiving type of the method (i.e. the type whose impl this method is in). This also allows for generic types without too much repetition.

Upvotes: 119

Related Questions