What's new in Go 1.13
in: Go programming articles
Go 1.13 was released on September 3 2019.
This document summarizes changes since 1.12.
Full release notes: https://golang.org/doc/go1.13


go mod

Improved go mod:

go build

Build multiple binaries with single go build
Provide a directory as -o argument to go build to build multiple binaries at once: go build -o dir path/to/main/packages/...
$ mkdir apps
$ go build -o apps/ ./app/...
$ ls -l apps/
total 38532
-rwxr-xr-x 1 valyala valyala 12403288 Aug 25 17:03 vminsert
-rwxr-xr-x 1 valyala valyala 13366272 Aug 25 17:03 vmselect
-rwxr-xr-x 1 valyala valyala 13652144 Aug 25 17:03 vmstorage
Trim file paths recorded in the binary
As part of debugging information recorded in the binary, go build includes file paths of source files.
By default they are full paths, which depend on the machine used to compile the code.
Option -trimpath to go build makes them system independent.
This helps to make reproducible builds.
$ go build ./cmd/printast
$ strings printast | grep main.go

$ go build -trimpath ./cmd/printast
$ strings printast | grep main.go
/Users/kjk/src/markdown/cmd/printast/main.go : default path for main.go
github.com/gomarkdown/markdown@/cmd/printast/main.go : system-independent path with -trimpath

Language and standard library

Error wrapping

There’s a standard way of wrapping errors.
To create an error that wraps another error, implement Unwrap() error interface which returns wrapped error (or nil if nothing is wrapped).
To easily wrap an error and add additional information, use %w argument to fmt.Errorf(). It creates a new error that wraps error provided as %w argument.
To check if error of type *myError is wrapped by error err, do errors.Is(err, &myError{}).
To extract wrapped error of specific type from error err, use errors.As(err, unwrapped)
err1 := &myError{}
err2 := fmt.Errorf(%w, err1)
errors.Unwrap(err2) == err1
errors.Is(err2, err1) == true
var me myError
errors.As(err2, &me) == true

Number literals

Better out of range panic message

Out of range panic messages now include the index that was out of bounds and the length (or capacity) of the slice.
runtime error: index out of range [3] with length 1

TLS 1.3 enabled by default

Performance optimizations

New escape analysis

It more aggressively optimizes ~188 instances, but more pessimistically optimizes 11.

Method inlining (mid-stack inlining)

The major part of it has been enabled in 1.12. sync.Mutex fast paths are inlined in 1.13
// F is inlined if fast path is small
func F(x int) {
    if x > 0 {
        slowPath()  // manually outlined
    // fast path

sync.Pool and GC

Objects in sync.Pool survive GC now.
var p sync.Pool
var obj object
p.Get().(*object) == obj

Faster defer

A single defer per func is allocated on stack instead of heap in 1.13, so it performs faster by up to 30%
type Counter struct {
        mu sync.Mutex
        n int

func (c *Counter) Inc() {
        defer c.mu.Unlock()  // <- this defer is faster now


Divisibility check optimizations
n % C == 0 is now 2x faster for constant C.
Faster encoding/json
Faster strings and bytes packages
Faster math/big
Optimizations in math/big usually improve performance for cryptography:
Faster **sync**
These optimizations were possible thanks to mid-stack inlining:
Faster startup time
Faster on ARM / ARM64
ARM optimizations should improve performance on mobile phones, raspberry pi and arm servers:

More Go resources

Written on Aug 16 2021.
Found a mistake, have a comment? Let me know.

Feedback about page:

Optional: your email if you want me to get back to you: