notexOPENOverview
Notex/Languages/Pointers Are a Last Resort
04.07LESSON 07 OF 20 · 2 MIN READ

Pointers Are a Last Resort

Always free to read

Be careful when using pointers in Go. As discussed earlier, they make it harder to understand data flow and can create extra work for the garbage collector. Rather than populating a struct by passing a pointer to it into a function, have the function instantiate and return the struct (see Examples 5-3 and 5-4).

Example 5-3. Don’t do this

func MakeFoo(f *Foo) error {
  f.Field1 = "val"
  f.Field2 = 20
  return nil
}

Example 5-4. Do this

func MakeFoo() (Foo, error) {
  f := Foo{
    Field1: "val",
    Field2: 20,
  }
  return f, nil
}

The only time you should use pointer parameters to modify a variable is when the function expects an interface. You’ll see this pattern when working with JSON:

f := struct {
  Name string `json:"name"`
  Age int `json:"age"`
}{}
err := json.Unmarshal([]byte(`{"name": "Bob", "age": 30}`), &f)

The Unmarshal function populates a variable from a slice of bytes containing JSON. It is declared to take a slice of bytes and an any parameter. The value passed in for the any parameter must be a pointer. If it is not, an error is returned.

Why do you need to pass a pointer into Unmarshal? Why doesn’t it just return a value? There are two reasons. First, this function predates generics being added to Go, and without generics, it has no way to know what type of value to create and return.

The second reason is that passing in a pointer gives you control over memory allocation. Iterating over data and converting it from JSON to a Go struct is a common design pattern, so Unmarshal is optimized for this case. If the Unmarshal function returned a value and Unmarshal was called in a loop, one struct instance would be created on each loop iteration. This would create a lot more work for the garbage collector, slowing down your program. (You’ll see another use of this pattern in “Slices as Buffers”, and I’ll talk more about efficient memory usage in “Reducing the Garbage Collector’s Workload”.)

Because JSON integration is so common, new Go developers sometimes treat this API as a common case instead of the exception that it should be.

When returning values from a function, favor value types. Use a pointer type as a return type only if there is state within the data type that needs to be modified. When you look at I/O in the related discussion, you’ll see this pattern with buffers for reading or writing data. In addition, some data types used with concurrency must always be passed as pointers. You’ll see those in the related discussion.

Progress is saved on this device.
KEEP EXPLORING

One note leads to another.

Back to the library →
⌕
Search across the entire library ⌘ K