03open 25 min

Data and state modeling: structs, interfaces, slices, and maps without enum-heavy design

Model data clearly in Go without expecting Rust's enum-rich approach to transfer directly.

by the end of this lesson you can

  • Uses a straightforward Go representation
  • Keeps branching easy to scan
  • Avoids pretending interfaces or structs are enum clones

Overview

Rust developers often reach for enums and exhaustive matches to make states explicit. Go gives you fewer modeling tools, so the practical skill is learning when a struct, interface, slice, or map is enough and when extra type precision is not buying much.

In Rust, you often

model variants and state transitions directly with enums and rely on exhaustive matching to keep code honest.

In Go, the common pattern is

to use plain structs, small interfaces, slices, and maps, accepting that some state discipline lives in code paths rather than in the type system.

why this difference matters

This lesson is about letting Go stay simple without pretending it has Rust's modeling vocabulary.

Rust

enum Job {
    Queued,
    Running,
    Failed(String),
    Done,
}

Go

type Job struct {
    Status string
    Error  string
}

Deeper comparison

Rust version

match job {
    Job::Queued => run(job_id)?,
    Job::Failed(message) => println!("{}", message),
    Job::Running => {}
    Job::Done => {}
}

Go version

switch job.Status {
case "queued":
    return run(job.ID)
case "failed":
    log.Println(job.Error)
}
return nil

Reflect

When is a simpler Go model good enough even if it cannot encode every legal state as precisely as Rust?

what a strong answer notices

A strong answer mentions readability, team conventions, and choosing clear control flow over type-system ambition.

Rewrite

Rewrite this Rust enum-based state example into a Go shape that stays readable.

Rewrite this Rust

enum Response {
    Ok(String),
    NotFound,
    Invalid(String),
}

what good looks like

  • Uses a straightforward Go representation
  • Keeps branching easy to scan
  • Avoids pretending interfaces or structs are enum clones

Practice

Design a Go data pipeline over slices where each step is clear without introducing extra modeling layers.

success criteria

  • Uses slices and structs intentionally
  • Keeps interfaces narrow or absent unless behavior abstraction is needed
  • Accepts simpler state representation where appropriate

Common mistakes

  • Over-modeling Go code because Rust made the state space explicit.
  • Using interfaces when plain structs and functions would be clearer.
  • Treating simple Go representations as inherently sloppy rather than context-appropriate.

takeaways

  • This lesson is about letting Go stay simple without pretending it has Rust's modeling vocabulary.
  • A strong answer mentions readability, team conventions, and choosing clear control flow over type-system ambition.
  • Uses slices and structs intentionally