liveBook · Manning

Named result parameter

As explained in 100 Go Mistakes and How to Avoid Them

A named result parameter is a Go function result parameter declared with an identifier that can be referenced within the function body and is initialized to its type's zero value.

A named result parameter gives a function result an identifier that can be used in the body. It starts at its type’s zero value. A bare `return` returns the current values of all named results; naming them does not require using bare returns. section 6.2

type locator interface {
    getCoordinates(address string) (lat, lng float32, err error)
}

Names distinguish the two `float32` results in the interface: latitude comes before longitude. When several results share a type, this can make a signature readable without inspecting its implementation. section 6.2

A small zero-value example is `func f(a int) (b int) { b = a; return }`: the bare return uses `b`’s current value. Where an interface permits it, a struct with named fields is another way to distinguish same-typed results. section 6.2

func (l loc) getCoordinates(ctx context.Context, address string) (
    lat, lng float32, err error) {
    isValid := l.validateAddress(address)          #1
    if !isValid {
        return 0, 0, errors.New("invalid address")
    }
 
    if ctx.Err() != nil {                          #2
        return 0, 0, err
    }
 
    // Get and return coordinates
}

The cancellation branch looks as though it returns an error, but `err` has never been assigned. Its zero value is `nil`, so `return 0, 0, err` reports no error. Without the named `err`, that reference would fail to compile. section 6.3

Return the error that was checked

Use `if err := ctx.Err(); err != nil { return 0, 0, err }`. This branch returns the checked error explicitly. A bare return is possible after assigning the named result, but mixing bare returns with returns that specify values makes the function harder to follow. section 6.3

Named results also let a deferred closure affect the error returned by its enclosing function. That power needs care: assigning `err = rows.Close()` unconditionally can replace an earlier scan error with `nil`. Preserve the scan error when one exists; otherwise, return the close error. If both fail, choose how to report the second failure rather than silently overwriting the first. section 7.7

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Works through zero-value initialization, bare returns, an accidental nil error, and error precedence during deferred cleanup.
Examples
Uses coordinate results, a cancellation check returning nil, and a database-row close that can overwrite a scan error.
What it assumes
Assumes familiarity with Go functions and errors while explaining named results and their zero-value initialization.
What you can do after
Diagnose/debug with it when a named error remains nil or deferred cleanup replaces an earlier error.
How it connects
Connects named results to interfaces, zero values, bare returns, context cancellation, deferred functions, and error handling.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.