Photo by Nathalie SPEHNER on Unsplash

The Value of Receiving

A Go Brain Teaser

Miki Tebeka
2 min readJul 19, 2022

--

https://pragprog.com/newsletter/
https://pragprog.com/newsletter/

What do you think the following program will print?

package mainimport (
"fmt"
)
type Coordinate struct {
Lat float64
Lng float64
}
func (c *Coordinate) String() string {
return fmt.Sprintf("%f/%f", c.Lat, c.Lng)
}
func main() {
c := Coordinate{32.5253837, 34.9408283}
fmt.Println(c)
}

This program will print: {32.5253837 34.9408283}.

Wait! What? Coordinate implements the fmt.Stringer interface. Shouldn't you see 32.5253837/34.9408283?

Let’s do a single character change to the program and try again:

fmt.Println(&c)

Now you’ll see 32.525384/34.940828 printed out.

When we pass a value of a Coordinate to fmt.Println, Go prints the default struct format. When we pass a pointer to a Coordinate to fmt.Println it does use our custom printing.

The Go spec is a good place to start. It says:

— The method set of a defined type T consists of all methods declared with receiver type T.
— The method set of a pointer to a defined type T (where T is neither a pointer nor an interface) is the set of all methods declared with receiver *T or T.

Our code fits the first case, Coordinate.Stringer is defined on a pointer receiver, yet we pass a value of Coordinate to fmt.Println. As far as Go is concerned, we didn't pass a parameter that implements fmt.Stringer to fmt.Println so fmt.Println prints the default struct formatting.

If you’re curious why Go behaves this way, you can read the FAQ. Or, even better, can watch Bill Kennedy explain why this behavior is a sign that Go loves you.

--

--