Go Language Fundamentals¶
Core Go language features - type system, slices, maps, pointers, interfaces, closures, and error handling. Covers runtime internals and common patterns for production Go code.
Key Facts¶
stringis an immutable read-only byte slice:struct { data *byte; len int }- Slice is a view over an underlying array:
struct { data *T; len int; cap int } - Go 1.24 maps use Swiss Table + SIMD-accelerated lookup (previously closed hashing with buckets)
- Maps are NOT safe for concurrent access - use
sync.Mapor external mutex - Interfaces are implicitly implemented - no
implementskeyword (structural typing) any=interface{}since Go 1.18
Patterns¶
Slices¶
s := make([]int, 3, 10) // len=3, cap=10
s = append(s, 4) // uses existing array if cap allows
s2 := s[1:3] // shares underlying array!
s3 := s[1:3:5] // three-index slice: limits cap
Key behaviors: - append doubles capacity up to ~256 elements, then grows by ~1.25x (Go 1.18+) - Sub-slices share the underlying array - mutations in one affect the other - Use copy(dst, src) or append(nil, src...) for independent copies - Comparing slices requires slices.Equal() - direct == is not allowed
Maps¶
m := make(map[string]int, 100) // preallocate hint - reduces rehashing
delete(m, "key")
val, ok := m["key"] // safe lookup - ok=false if absent
Pointers¶
Only use pointers when: 1. Mutating struct in a function 2. Struct is large (>1 KB rule of thumb) 3. Nullable semantics needed
Pointer to slice/map/channel is almost never needed - they are already reference types internally.
Escape analysis: compiler decides stack vs heap. Profile with go build -gcflags="-m".
Interfaces¶
type ReadWriter interface { Reader; Writer } // interface composition
type MyService struct { BaseService } // struct embedding
Typed nil gotcha:
var p *MyError = nil
var err error = p // err is NOT nil! type info is non-nil
if err != nil { ... } // this branch EXECUTES
Always return error interface, not concrete error types.
Type assertion: val.(ConcreteType) panics if wrong. Safe: val, ok := v.(T). Type switch: switch v := x.(type) { case *T: ... case *S: ... }.
Closures¶
Common gotcha - loop variable capture:
// Wrong: all goroutines capture same 'i'
for i := 0; i < 5; i++ {
go func() { fmt.Println(i) }()
}
// Correct: pass as argument
for i := 0; i < 5; i++ {
go func(n int) { fmt.Println(n) }(i)
}
// In Go 1.22+: loop variable is per-iteration (fixed)
Error Handling¶
Errors are values - return them, don't use exceptions for control flow.
if err != nil {
return fmt.Errorf("context: %w", err) // wrap with %w for unwrapping
}
var myErr *MyError
if errors.As(err, &myErr) { ... } // checks chain
if errors.Is(err, io.EOF) { ... } // checks chain for specific value
panic/recover: panic for unrecoverable programmer errors. HTTP servers commonly use recover in handler middleware. fatal error (stack overflow) cannot be recovered.
Context¶
ctx, cancel := context.WithTimeout(parent, 5*time.Second)
defer cancel()
ctx = context.WithValue(ctx, key, value) // request-scoped data only
Rules: - Pass ctx as first argument to all I/O functions - Never store ctx in struct - Call cancel() as soon as work is done - Context values for request-scoped data only (user ID, trace ID), not optional parameters
Functional Options¶
type Option func(*Server)
func WithTimeout(d time.Duration) Option {
return func(s *Server) { s.timeout = d }
}
func NewServer(opts ...Option) *Server {
s := &Server{timeout: 5*time.Second}
for _, opt := range opts { opt(s) }
return s
}
Gotchas¶
- Sub-slices share underlying array - modifying a sub-slice mutates the original
- Maps are not concurrent-safe;
sync.Mapis optimized for read-heavy workloads, not a general replacement - Typed nil interface is NOT nil (interface holds type info even when value is nil)
unsafe.Pointerbypasses type system - only for C bindings and memory-mapped I/O- Go 1.22 fixed loop variable capture for goroutines - in older versions each closure shares the same variable
See Also¶
- go concurrency - GMP scheduler, channels, sync primitives
- go microservices - gRPC, clean architecture, project layout
- go database patterns - PostgreSQL/pgx, MongoDB, Redis