Pointer Receivers in Go Programming

Welcome to part 8 of the Go programming tutorial series, where we're talking about methods in Go lang.

So far, we've used our car type example, showing how we could calcuate the vehicle's speed using a value receiver method. What if we wanted to actually modify the object with a method? How might we do that? To do this, we use a pointer receiver. We can do this with a slight modification to our method. Let's suppose we have the same input, but, instead of a car with a top speed of 225, we just bolted in an amazing supercharger and our top speed is now 500 KM/H

Note the *car in func (c *car). Now, we're modifying the struct itself via pointer. Now in the code we could do something like a_car.new_top_speed(500), and this would actually modify the object itself. Let's add that to the main function, making the full code up to this point:

As you can see, when we change the top speed of the car, the current speed based on the pedal position also changes. What if we changed top speed of the struct without the pointer? For example, if we did it in the mph function, which is just a value receiver:

As you can see, the current speed changed, but the top speed wasn't modified. This is of course because we were working with a copy of the object, not the object itself. Okay, what if we turned the mph and kmh method receivers to pointer receivers instead of value receivers? All we need to do is make car*car:

In this case, it changed not only the top speed, but also both MPH and KMH (even though we didn't modify the top speed in the kmh receiver), since the mph receiver is run before the kmh one.

At this point though, one must wonder, why would we ever use a value receiver? Why not always use the pointer receiver, even if you're not going to change something? Well, you could just always use pointer receivers, but, value receivers are better for basic types and small structs. This is because they're much cheaper to work with and can reduce the amount of overall garbage created. That said, if the struct is very large, a pointer is more likely to be more efficient since we're not creating a copy. To learn more, check out the golang.org doc FAQ on "Should I define methods on values or pointers?".

Interestingly enough, that doc suggests that, to keep things consistent, "if some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used."

I am not really sure I agree with that sort of logic. Personally, I would test both. If the gains are insignificant by using value receivers where possible and you are using pointer receivers, sure, use all pointer receivers. If you can make sizeable gains by using value receivers where possible, however, I would personally use them.

Just for kicks, since I did it in the video, here's a function that could achieve similar results for us: