Go Mastery 2: Interfaces, Errors, Generics, Modules
/ 2 min read
Table of Contents
1. Interfaces (the heart of Go)
- Implicit satisfaction (structural typing)
- Small interfaces (
io.Reader,io.Writer,fmt.Stringer,error) - “Accept interfaces, return structs”
- Define interfaces on the consumer side
- Empty interface /
any, type assertions, type switches - Interface internals: (type, value) pair
- The nil interface gotcha: an interface holding a nil pointer is not nil
- Embedding interfaces, composition over inheritance
Visual: implicit interface satisfaction
classDiagram
class Reader {
<<interface>>
Read(p []byte) (n int, err error)
}
class File
class Buffer
class HTTPBody
Reader <|.. File : implicit
Reader <|.. Buffer : implicit
Reader <|.. HTTPBody : implicit
No implements keyword: any type with the right methods satisfies the interface.
2. Error handling
-
erroris just an interface -
fmt.Errorf("...: %w", err)wrapping -
errors.Is,errors.As,errors.Join,errors.Unwrap - Sentinel errors vs custom error types
- Don’t ignore errors; don’t log and return the same error
-
panic/recover: only for truly unrecoverable states or package boundaries - Adding context to errors as they bubble up
Visual: error wrapping chain
flowchart LR A["handler error<br/>'create user: ...'"] -->|"%w"| B["service error<br/>'insert row: ...'"] B -->|"%w"| C["driver error<br/>sql.ErrNoRows"] A -. "errors.Is(err, sql.ErrNoRows)" .-> C
errors.Is and errors.As walk this chain for you.
3. Generics (Go 1.18+)
- Type parameters and constraints
-
any,comparable,cmp.Ordered, custom constraint interfaces - Generic functions and generic types
- Type inference
- When NOT to use generics (prefer interfaces or plain code first)
- Packages:
slices,maps,cmp
4. Packages and modules
-
go mod init,go.mod,go.sum - Semantic versioning,
go get,go mod tidy,go mod vendor - Major version suffix (
/v2) -
internal/packages - Exported vs unexported (capitalization)
- Package naming: short, lowercase, no underscores
- Avoiding import cycles
- Workspaces (
go.work) - Standard project layout (don’t over-engineer):
cmd/,internal/,pkg/(optional)
5. Idioms to internalize
- Functional options pattern
- Constructor functions (
NewX) - Make the zero value useful
- Early return, avoid deep nesting
- Table-driven design
-
iotaenums plusString()method - Embedding for delegation
- Method values and method expressions
6. Reflection and unsafe (awareness level)
-
reflect.TypeOf,reflect.ValueOf: know what it can do and why it is slow - Struct tags and how
encoding/jsonuses them -
unsafeexists; know to avoid it
7. Iterators (Go 1.23+)
-
iter.Seq,iter.Seq2 - Range-over-func
-
slices.Collect,maps.Keys
Practice
- Write a generic
Stack[T],Set[T comparable], andMap/Filter/Reduce - Build a custom error type hierarchy with
errors.Is/As - Implement your own
io.Readerthat transforms data (e.g. uppercase) - Create a library with the functional options pattern
Previous: Go Mastery 1: Fundamentals Revision
Next: Go Mastery 3: Concurrency Done Right