Chapter 01

Tooling & the compiler as a friend.

Your dotnet muscle memory transfers almost completely. The big mindset shift isn't the CLI — it's learning to treat the compiler as the strictest, most helpful code reviewer you've ever had.

1.1Installing & the cargo CLI

Rust ships as a toolchain managed by rustup (think of it as a version manager for the SDK). The day-to-day driver is cargo, which is the dotnet CLI, NuGet client, and build system rolled into one binary.

You'd type in .NETIn RustWhat it does
dotnet new consolecargo new appscaffold a project
dotnet buildcargo buildcompile
dotnet runcargo runbuild + run
dotnet testcargo testrun tests (built into the language)
dotnet add package Xcargo add xadd a dependency
dotnet build -c Releasecargo build --releaseoptimized build
Roslyn analyzerscargo clippylints, but far chattier and usually right
dotnet formatcargo fmtcanonical formatter (no debates)
Equivalence

A crate is the unit of compilation — closest to a .NET assembly. A module (mod) is an in-crate namespace, like a namespace block. crates.io is NuGet. Cargo.lock is your packages.lock.json, but on by default for apps.

1.2Cargo.toml vs .csproj

Project metadata lives in Cargo.toml (TOML, not XML). Here is this very server's manifest, annotated:

Cargo.toml# like <PropertyGroup> in a .csproj
[package]
name = "rust-for-csharp"
version = "0.1.0"
edition = "2021"   # ~ <LangVersion>

# each line ~ <PackageReference Include=".." Version=".." />
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

That features array has no clean C# analogue. Crates ship with optional, compile-time feature flags so you only pull in (and compile) the parts you use — closer to MSBuild conditional compilation symbols than to NuGet.

1.3Hello, world — and the shape of a program

C#

using System;

class Program {
  static void Main() {
    Console.WriteLine("Hello");
  }
}

Rust

fn main() {
    println!("Hello");
}

Two things to notice. println! ends in ! because it's a macro, not a method — it does compile-time work (format-string checking) that a regular function can't. And there's no class wrapper: Rust has free functions, like top-level statements but everywhere.

1.4The compiler is the point

This is the cultural shift. In C# you lean on the runtime and tests to catch mistakes; an exception at runtime is normal. In Rust, an enormous class of bugs is simply rejected at compile time — and the error messages are written to teach, often suggesting the exact fix.

Mindset

Expect to fight the compiler for a week or two, then stop noticing it. "If it compiles, it works" is overstated, but the category of thing that compiles-and-then-corrupts-memory or throws a NullReferenceException largely disappears. You're trading runtime surprises for compile-time friction.

Next we tackle the reason that's possible — the one idea with no C# counterpart.