« Back to Index

Go: Pointers - Guidelines

View original Gist on GitHub

Tags: #go #guide

Golang Pointers - Guidelines.md

Reference

Information was pulled from https://medium.com/@kent.rancourt/go-pointers-when-to-use-pointers-4f29256ddff3

Problems with Pointers

an unrelated comment would be, from a code design perspective, functions should not dip inside of data structures to access nested fields (I’ve seen this done to access a pointer to a struct): law of demeter.

  1. Avoid pointers (you can always justify your way into using them later if necessary).
  2. Don’t expect pointers to be more efficient: benchmark! (pass-by-value ‘copies’ are placed in the ‘stack’ not ‘heap’ and thus are handled faster by the CPU).
  3. When returning a pointer, also return a bool to indicate success (in case of error, returning an empty struct will cause a nil dereference error for caller if they don’t expect an empty struct).
  4. Use a pointer when a function needs to modify its receiver (e.g. create method on struct whose receiver is a pointer, that way user can pass around/work with a non-pointer and when calling the method will the compiler switch to a pointer receiver to allow data modification).
  5. Use a pointer when you need a singleton.

Best Practice for Singleton

For components with great importance, we should control the terms on which others interact with them. To do this, create an exported interface with a non-exported implementation, where pointers to the component in question implement the interface.

package main

import (
	"fmt"
)

type S struct {
	// ...
}

type Cache interface {
	Add(key string, val S)
	Get(key string)
	Clear()
}

type cache struct {
	foo string
	bar int
}

func NewCache() Cache { // <--- This is what the caller sees
	return &cache{"beep", 456} // <--- It's a pointer, but they don't need to know
}

func (c *cache) Add(key string, val S) {
	// ...
}

func (c *cache) Get(key string) {
	// ...
}

func (c *cache) Clear() {
	// ...
}

func main() {
	c := NewCache()
	fmt.Printf("%+v\n", c) // <--- caller can see the structure &{foo:beep bar:456}
	fmt.Printf("%+v\n", c.foo) // <--- but they can't interact with it (compile time error: c.foo undefined (type Cache has no field or method foo))
}