tracks / rust-to-go
Rust
Go

A guided path for Rust developers becoming productive in Go.

Trade type-system precision for simpler, faster-moving service code.

This track is for Rust developers who know ownership, enums, and explicit modeling, and want to become productive in Go without expecting Rust-level guarantees. It focuses on deliberate simplicity, flatter structure, simpler data modeling, explicit error returns, and Go's concurrency style.

6 lessons~2.5 hrscomparison-firststatus: stableupdated Apr 2026

before you start

  • $You already write real Rust code. This path assumes professional instincts, not beginner-level programming lessons.
  • $Expect comparison-first modules: each stop starts from familiar Rust habits, then shows where Go agrees or pushes back.
  • $Plan to practice the target ecosystem directly — syntax, testing, and design choices should feel native by the end, not translated.

by the end you can

  • Read and write idiomatic Go without translating every line back through Rust.
  • Spot which Rust instincts transfer cleanly and which ones need a different Go mental model.
  • Use the six modules as a working checklist when you build your first real Go tool, service, or feature.

syllabus

6 modules, one capstone.

6 lessons · ~2.5 hrs
module 01
1 lesson · ~25 min

Mindset shift

Move from Rust's precision-first design culture to Go's simpler, readability-first defaults.

module 02
1 lesson · ~25 min

Syntax and structure

Map Rust modules, structs, and impl blocks onto Go packages, structs, functions, and methods.

module 03
1 lesson · ~25 min

Data and state modeling

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

module 04
1 lesson · ~25 min

Error handling

Translate Result and Option habits into Go's error, wrapping, and nil-based control flow.

module 05
1 lesson · ~25 min

Testing in Go

Translate Rust test habits into Go's testing package and table-driven style.

module 06
1 lesson · ~25 min

Concurrency and context

Learn Go's concurrency model for Rust developers used to threads or async runtimes.

track reference

Keep the shared translation aids in one place.

These are track-wide lookup tables and task patterns, not lesson-specific reading. Use them when you need a quick reset on the recurring source-to-target language translations.

Data type mappings

Recheck the building blocks when a translation starts to wobble.

Rust

String / &str

Go

string

Common operations

  • Move from explicit owned/borrowed distinctions back to simpler Go strings.
  • Formatting moves from format! to fmt.Sprintf.
  • String APIs stay explicit but with less type-level distinction.

Rust

Vec<T>

Go

slice

Common operations

  • Push/append remain familiar but slices are the default collection surface in Go.
  • Iterator chains often become loops.
  • Keep collection code simple rather than generic-heavy.

Rust

HashMap / keyed data

Go

map or struct

Common operations

  • Use maps when keyed data is dynamic and structs when the shape is stable.
  • Avoid carrying Rust's precise map-oriented modeling into code that should become a plain Go struct.
  • Choose simpler data contracts when they improve readability.

Rust

Result / Option

Go

error / nil

Common operations

  • Separate failure with error returns and ordinary absence with nil or extra values.
  • Keep the control flow visible even without Rust's enum-based return types.
  • Use explicit checks instead of assuming Result-like ergonomics.

Rust

enum / trait-heavy modeling

Go

struct or interface

Common operations

  • Accept less precise state modeling when it improves readability.
  • Use small interfaces when behavior matters and plain structs when data shape is enough.
  • Do not force Rust-style enum precision onto code that should stay simple in Go.

Comparative cheat sheet

Keep the most common tasks visible while you practice.

TaskRustGo
Define a functionfn greet(name: &str) -> String { format!("hello {}", name) }func greet(name string) string { return "hello " + name }
Format a stringlet msg = format!("user={}", id);msg := fmt.Sprintf("user=%d", id)
Add to a collectionitems.push(value);items = append(items, value)
Handle failing datalet user = load_user(id)?;user, err := loadUser(id) if err != nil { return err }
Test a function#[test] fn slugify_works() { ... }func TestSlugify(t *testing.T) { ... }

capstone

Ship a small Go project that proves the mental model stuck.

Build one focused artifact in Go using the same comparison-first habits from the track: start from a familiar Rust shape, then deliberately redesign it the way Go expects.

  • Translate a familiar Rust data flow into idiomatic Go structure instead of preserving the old shape by force.
  • Apply the early modules to data modeling, control flow, and API boundaries before you add tooling, polish, or deployment concerns.
  • Use the later modules to verify, test, and package the result the way Go developers expect to see it shipped.

ready?

Start with module 01 — Mindset shift.

Begin