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