Skip to content

Go Language Fundamentals (Caddy Contextualized)

This guide highlights key Go concepts compared to Python, pointing directly to how they are implemented in Caddy's codebase.


1. Pointers vs. Value Semantics

Go passes variables by value (copies them) unless you use pointers (*).

Code Examples in Caddy:

  • Pointer Receiver: Look at caddy.go:L524-530:
    func (m *Logging) openLogs(ctx Context) error { ... }
    
    The receiver (m *Logging) uses an asterisk * because it needs to modify the fields on the active Logging struct itself without making a copy.
  • Passing by Pointer: Look at caddy.go:L104:
    func Run(cfg *Config) error {
    
    cfg *Config indicates that the function takes a pointer to the config object so it can read and update the original memory representation rather than copying the entire Config struct.

2. Error Handling (The Early Return Pattern)

Go functions return errors alongside results, checked with if err != nil.

Code Examples in Caddy:

  • Checking and Returning Early: Look at caddy.go:L104-110:
    cfgJSON, err := json.Marshal(cfg)
    if err != nil {
        return err
    }
    return Load(cfgJSON, true)
    
    If json.Marshal(cfg) fails, the function exits immediately returning the err. If it succeeds, the code flows down without being nested inside an else block.

3. Arrays, Slices, and Maps

  • Slice (Dynamic List): Look at caddy.go:L445:
    started := make([]string, 0, len(ctx.cfg.apps))
    
    []string creates a dynamically-sized list of strings to keep track of which apps started successfully.
  • Map (Hash Table/Dictionary): Look at caddy.go:L84:
    apps map[string]App
    
    Maps keys (strings) to values (App interface instances).

4. Visibility (Capitalization)

Go uses casing to define access scope instead of keywords like public or private.

Code Examples in Caddy:

Look at caddy.go:L68-84: * Exported (Public): Config and fields like Admin, Logging, StorageRaw are uppercase so that external packages can use them. * Unexported (Private): apps and failedApps are lowercase so they can only be read/written inside the caddy package.