1. Go Fundamentals: Types, Interfaces, and Error Handling
Go Fundamentals: Types, Interfaces, and Error Handling
This course is about being interview-ready in Go: not just “I’ve used it”, but “I understand why it works this way”. This first article refreshes the foundations you’ll be evaluated on constantly:
These topics also set you up for the next parts of the course (goroutines, channels, and sync), because concurrency bugs often start as type, interface, or error misuse.
Types and zero values
Go is a statically typed language: every value has a type known at compile time (even when inferred).
Basic vs composite types
Common basic types:
boolstringint, int64, uint, uintptrfloat64complex128Common composite types:
[N]T[]Tmap[K]Vstruct{ ... }*Tfunc(...) ...interface{ ... }The Go spec is the most precise reference if an interviewer pushes you on definitions: The Go Programming Language Specification.
Zero values
Every type has a zero value: what you get when you declare a variable without initializing it.
0bool: falsestring: ""nilKey detail: nil is not “empty”; it’s “not initialized”. Some operations work on nil values, some do not.
Value semantics vs “reference-like” types
In Go, assignment copies the value. But some values contain internal pointers to shared backing storage.
[3]int copies all elements.This matters a lot later with goroutines: if two goroutines share a map or a slice backing array, you must synchronize access.
new vs make
These are commonly tested.
new(T) allocates a zero value of type T and returns *T.make(T, ...) initializes runtime-backed types: slice, map, chan.Rule of thumb: if you need a usable map/channel/slice, you want make.
Variables, type inference, and constants
Declarations and inference
var x int = 10 is explicit.var x = 10 is inferred.x := 10 is short declaration (only inside functions).Be careful in interviews with := and shadowing:
Untyped constants
Go constants can be untyped until context requires a type.
This is one reason Go constant expressions feel flexible.
Methods and receiver semantics
Methods are functions with a receiver:
Value receiver vs pointer receiver
Method sets (core interview topic)
The method set determines which interfaces a type implements.
T includes methods with receiver T.T includes methods with receiver T and T.That implies:
*T implements it.!Diagram showing how method sets differ for T vs *T
Interfaces
An interface is a set of method signatures. A type implements an interface implicitly by having the required methods.
Effective, idiomatic interfaces are usually small (often 1–2 methods). See: Effective Go.
Defining and using interfaces
Reference: package io.
Interface composition
Interfaces can embed other interfaces:
This is a common way to express capabilities.
The empty interface and any
interface{} can hold any value.any is an alias for interface{}.Prefer precise types and interfaces over any in production code. In interviews, you’ll often be asked how to safely recover a concrete type from any.
Type assertions and type switches
Type assertion:
Type switch:
The nil interface pitfall
An interface value is conceptually a pair:
The interface is nil only when both are nil.
This shows up a lot with error returns.
Error handling
In Go, errors are values. By convention, a function that can fail returns (T, error) (or just error).
The built-in error is an interface:
Reference: package errors.
Creating errors
errors.New("message")fmt.Errorf("formatted %s", x)Wrapping errors (and why it matters)
Wrapping preserves context while keeping the original error discoverable.
%w is special: it marks the wrapped error so it can be inspected later.
Reference: package fmt.
Checking errors: errors.Is and errors.As
errors.Is(err, target) to check whether any error in the wrapping chain matches target.errors.As(err, &targetType) to extract a specific concrete error type from the chain.The errors package documents the wrapping and inspection rules: package errors.
Sentinel errors vs custom error types
Two common patterns:
var (like io.EOF) used for equality/errors.Is checks.Prefer custom types when callers need to branch on details, not on a single constant.
panic vs returning errors
panic for programmer mistakes or impossible states.panic can be recovered with defer + recover, but this is not a replacement for normal error handling.
Reference: Defer, Panic, and Recover.
Practical guidelines you can say out loud in an interview
any in public APIs unless you truly need it.fmt.Errorf("...: %w", err)) and inspect with errors.Is / errors.As.In the next articles, these fundamentals will reappear constantly: channels are typed, sync relies on pointer semantics, and context cancellation/timeout patterns are built around interfaces and error propagation.