tracks / python-to-rust
Python
Rust

A guided path for Python developers who want to think in Rust.

Learn ownership, enums, and compiler-guided design.

This track is built for experienced Python developers moving into Rust. It focuses on the conceptual shifts that feel hardest at first: ownership, explicit state modeling, compiler-guided design, and the disciplined patterns that make Rust code trustworthy.

6 lessons~2.5 hrscomparison-firststatus: stableupdated Apr 2026

before you start

  • $You already write real Python code. This path assumes professional instincts, not beginner-level programming lessons.
  • $Expect comparison-first modules: each stop starts from familiar Python 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 Python.
  • Spot which Python 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.

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

Mindset shift

Move from Python's runtime flexibility to Rust's correctness-first feedback cycle.

module 02
1 lesson · ~25 min

Ownership and borrowing

Understand how Rust controls who owns data, who can borrow it, and when mutation is allowed.

module 03
1 lesson · ~25 min

Enums and pattern matching

Model variant-rich data directly with enums and handle it exhaustively with match expressions.

module 04
1 lesson · ~25 min

Option, Result, and errors

Translate Python's None and exception habits into Rust's explicit sum types and propagation patterns.

module 05
1 lesson · ~25 min

Traits and generics

Learn how Rust models shared behavior and reusable logic through traits and generics instead of class inheritance or pure duck typing.

module 06
1 lesson · ~25 min

Testing in Rust

Translate pytest habits into Rust's built-in test model, assertion macros, and common organization patterns.

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.

Python

string

Rust

String or &str

Common operations

  • Format values with f-strings in Python and format!/println! in Rust.
  • Use owned String when data must be kept and &str when borrowing is enough.
  • Treat ownership and borrowing as part of the string API decision.

Python

list

Rust

Vec<T>

Common operations

  • Append with list.append(...) in Python and push(...) in Rust.
  • Transform with comprehensions in Python and iterator chains or loops in Rust.
  • Keep element type explicit in Rust instead of relying on mixed runtime shapes.

Python

dict

Rust

HashMap<K, V> or struct

Common operations

  • Use HashMap when keyed lookup is dynamic and structs/enums when the shape is known.
  • Prefer named structs when the shape is stable and part of the contract.
  • Keep the data model explicit instead of leaving Python dict shape informal.

Python

None / missing value

Rust

Option<T> / Result<T, E>

Common operations

  • Model ordinary absence with Option and failure with Result instead of collapsing them together.
  • Let match or combinators keep missing-data handling explicit.
  • Use the type system to separate not found from operation failed.

Comparative cheat sheet

Keep the most common tasks visible while you practice.

TaskPythonRust
Define a functiondef greet(name: str) -> str: return f"hello {name}"fn greet(name: &str) -> String { format!("hello {}", name) }
Format a stringmessage = f"user={user_id}"let message = format!("user={}", user_id);
Add to a collectionitems.append(value)items.push(value);
Handle missing dataif user is None: return Noneif user.is_none() { return None; }
Test a functiondef test_slugify(): assert slugify("Hello") == "hello"#[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 Python shape, then deliberately redesign it the way Rust expects.

  • Translate a familiar Python 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.

Begin