About self -> Self

I'm still going through the Beginning-Rust guide, and I found this piece:

trait HasSquareRoot {
    fn sq_root(self) -> Self;
}

What does the self -> Self part mean?
(Here is the full snippet).

trait HasSquareRoot {
    fn sq_root(self) -> Self;
}
impl HasSquareRoot for f32 {
    fn sq_root(self) -> Self {
        f32::sqrt(self)
    }
}
impl HasSquareRoot for f64 {
    fn sq_root(self) -> Self {
        f64::sqrt(self)
    }
}

I did a quick search before asking this question, and I'm not sure whether or not my theory is right.
The self -> Self thing means that each implementation gets to decide what to give back, right?

Within a trait A block, Self stands for a non-specific type that implements the trait A; within an impl A for T block, it stands for T, the type that A is being implemented for. So in this impl:

impl HasSquareRoot for f32 {
    fn sq_root(self) -> Self {
        f32::sqrt(self)
    }
}

Self stands for f32. The parameter self in an associated function like sq_root implicitly has the type Self. So the signature fn sq_root(self) -> Self means that for each type that implements HasSquareRoot, sq_root is a method that can be called on a value of that type and that returns a value of the same type. When you call .sq_root() on a value of type f32, you get an f32 back; when you call it on a value of type f64, you get an f64 back; and so on.

1 Like

Thanks for the quick response!

So it's something like:

fn function(self) -> Self;

Would mean that whatever I input, I'll get an output that it's exactly the same type to the one that I input.
Got it!

1 Like

Yep!

You can also use Self in type signatures -- and elsewhere -- for associated functions that don't belong to a trait, like this:

struct Nth(u32);

impl Nth {
    fn successor(self) -> Self {
        Self(self.0 + 1)
    }
}

Pretty much... self is a value that has the type of whatever impl block we're in (e.g. Foo in impl SomeTrait for Foo or impl Foo), but Self represents the type itself.

So fn foo(self) -> Self is a method which returns an instance of whatever type we're attaching the method to.