为什么带有指针接收器的方法在接收值时仍然可以工作?

I was just playing with Exercise 51 in the Tour of Go. The explanation claims the Scale method has no effect when it receives a Vertex instead of a pointer to a Vertex.

Yet when I change the declaration v := &Vertex{3, 4} to v := Vertex{3, 4} in main the only change in the output is the missing & to mark the pointer.

So why does Scale change the variable it receives even if the variable isn't a pointer?

It does not "receive" a value. Go is strongly typed, so if somewhere a pointer to T is prescribed, a pointer to T (*T) is the only option which can happen as a value for such typed place.

The "magic" is in the compiler which effectively "rewrites" your code under certain conditions:

A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():

Related: Method sets

The difference that the tour suggests isn't actually in changing v := &Vertex{3, 4} to v:= Vertex{3, 4}, but rather in changing the definitions of the two methods so that they work on values instead of pointers. So, for example, for Scale, func (v *Vertex) Scale(f float64) {... becomes func (v Vertex) Scale(f float64) {... (note that (v *Vertex), a pointer value, becomes (v Vertex), a non-pointer value). In both cases, you should leave the declaration of v as v := &Vertex{3, 4}.

You'll notice that in the first case, when the methods take pointers, the output is &{15 20} 25. However, when the methods take values rather than pointers, the output is &{3 4} 5.

In both cases, v is a pointer to a Vertex object. In the first case, the pointer is passed to the methods, and everything works as expected - any modifications made to the Vertex object are made to the original value, so those changes persist after the method returns. In the second case, though v is still a pointer, the Go compiler is smart enough to convert v.Scale(5) to (*v).Scale(5), where v is dereferenced, and the resulting value is passed to Scale.