Early previewThis guide is in development. Items tagged verify are still being checked against official docs.
nebx Learn
GitHub
Menu
Home/Go/Tips & tricks
Go

Go

Simple, fast to compile, built for concurrent network services.

Paradigm
Procedural, composition over inheritance
Typing
Static, strong, structural interfaces
Memory
Concurrent low-latency GC
Runs
Single static native binary
Concurrency
Goroutines and channels

Tips & tricks

Small idioms with a big payoff.

Table-driven tests

One test function, many cases, readable failures with t.Run.

func TestAdd(t *testing.T) {
	tests := []struct {
		name string
		a, b int
		want int
	}{
		{"zero", 0, 0, 0},
		{"positive", 2, 3, 5},
		{"negative", -2, -3, -5},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Add(tt.a, tt.b); got != tt.want {
				t.Errorf("Add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
			}
		})
	}
}

Error wrapping

Add context while keeping the original error inspectable.

var ErrNotFound = errors.New("not found")

func load(id int) error {
	return fmt.Errorf("load user %d: %w", id, ErrNotFound)   // wrap with context
}

if err := load(7); errors.Is(err, ErrNotFound) {   // still matches after wrapping
	// handle 404
}

Timeouts with context

Every outbound call gets a deadline in two lines.

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
resp, err := http.DefaultClient.Do(req)   // aborts automatically after 2s

Saved in this browser only. Part of Clean code foundations (0/5).