A guided path for Go developers who want to think in Rust.
Add stronger guarantees to a familiar backend mental model.
This track is built for experienced Go developers who want Rust's stronger guarantees without beginner-level detours. It focuses on compiler-guided design, explicit state modeling, Result and Option, Rust's testing style, and concurrency patterns that feel different from ordinary Go habits.
before you start
- $You already write real Go code. This path assumes professional instincts, not beginner-level programming lessons.
- $Expect comparison-first modules: each stop starts from familiar Go habits, then shows where Rust 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 Rust without translating every line back through Go.
- →Spot which Go instincts transfer cleanly and which ones need a different Rust mental model.
- →Use the six modules as a working checklist when you build your first real Rust tool, service, or feature.
syllabus
6 modules, one capstone.
Mindset shift
Move from Go's simplicity-and-discipline culture to Rust's compiler-guided design loop.
Syntax and structure
Map familiar Go file and type organization onto Rust modules, structs, and impl blocks.
Data and state modeling
Use enums and pattern matching to model explicit state machines more directly than typical Go code.
Error handling
Translate from error returns and zero-value habits into Result, Option, and ?.
Testing in Rust
Map Go's standard-library testing habits onto Rust's #[test], assertions, and nearby test modules.
Concurrency and shared state
Learn how Rust handles concurrent work and shared state for developers coming from goroutines and channels.
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.
Go
string
Rust
String or &str
Common operations
- Go strings stay simple; Rust adds owned versus borrowed string choices.
- Formatting moves from fmt.Sprintf to format!.
- Borrowing decisions become part of normal string work in Rust.
Go
slice / array-like collection
Rust
Vec<T>
Common operations
- Append with append(...) in Go and push(...) in Rust.
- Rust iterator chains replace many loop-based transformations.
- Element ownership and borrowing affect how collection code is shaped.
Go
map / keyed data
Rust
HashMap or struct
Common operations
- Use HashMap when keyed data is truly dynamic and structs when the shape is known.
- Keep legal fields and access patterns explicit in Rust instead of staying too map-shaped.
- Choose the more precise data model earlier than you might in Go.
Go
error / nil
Rust
Result / Option
Common operations
- Use Result for failure and Option for ordinary absence.
- Keep absence and failure separate instead of mixing them in one contract.
- Let the caller see success and failure explicitly in the return type.
Go
struct state
Rust
enum
Common operations
- Use enums when legal states matter instead of structs plus booleans.
- Let match stay exhaustive so transitions are explicit.
- Reach for structs when data shape is stable and for enums when variant state is the core idea.
Comparative cheat sheet
Keep the most common tasks visible while you practice.
| Task | Go | Rust |
|---|---|---|
| Define a function | func greet(name string) string {
return "hello " + name
} | fn greet(name: &str) -> String {
format!("hello {}", name)
} |
| Format a string | msg := fmt.Sprintf("user=%d", id) | let msg = format!("user={}", id); |
| Add to a collection | items = append(items, value) | items.push(value); |
| Handle failing data | if err != nil {
return err
} | if result.is_err() {
return result;
} |
| Test a function | func TestSlugify(t *testing.T) { ... } | #[test]
fn slugify_works() {
assert_eq!(slugify("Hello"), "hello");
} |
capstone
Ship a small Rust project that proves the mental model stuck.
Build one focused artifact in Rust using the same comparison-first habits from the track: start from a familiar Go shape, then deliberately redesign it the way Rust expects.
- ●Translate a familiar Go data flow into idiomatic Rust 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 Rust developers expect to see it shipped.
ready?
Start with module 01 — Mindset shift.