Rust Basics
10 examples to get you started with Rust fundamentals - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples to get you started with Rust fundamentals - 7 basic and 3 intermediate.
rustup default stable)cargo --version prints 1.97 or newermainEvery Rust program starts at main.
fn main() {
println!("Hello, Rust!");
}cargo new hello scaffolds a binary cratecargo run compiles and executesprintln! is a macro, not a function; are returned valuesRelated: Formatting & Printing -
Displayand format specifiers
Variables are immutable unless you opt in with mut.
fn main() {
let x = 5;
// x = 6; // compile error
let mut count = 0;
count += 1;
println!("{count}");
}let creates a binding; immutability is the defaultmut allows reassignment of the bindinglet without mut until mutation is requiredRelated: Variables, Mutability & Shadowing - shadowing and constants
Rust has fixed-size integers, floats, bool, and char (Unicode scalar).
fn main() {
let age: u32 = 30;
let ratio: f64 = 0.75;
let active: bool = true;
let letter: char = 'R';
println!("{age} {ratio} {active} {letter}");
}i8..i128, u8..u128, isize, usizechar is 4 bytes (Unicode), not 1 byte like C42u64, 3.14f32Related: Scalar & Compound Types - tuples and arrays
The last expression in a block is the return value.
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let sum = add(2, 3);
println!("{sum}");
}main)return is explicit but rarely needed; turns an expression into a statement (discards value)Related: Functions & Expressions - expressions vs statements
if as an ExpressionBranches can produce values when both arms return the same type.
fn main() {
let n = 7;
let label = if n % 2 == 0 { "even" } else { "odd" };
println!("{n} is {label}");
}if/else must return compatible types in all armsboolif let for single-pattern matches (covered later)let + mutationRelated: Control Flow - loops and
match
Each value has one owner; assigning moves ownership for non-Copy types.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // move - s1 is no longer valid
// println!("{s1}"); // error: value moved
println!("{s2}");
}String owns heap data; &str borrows a string slicei32) implement Copy and duplicate instead of move& shares read access without transferring ownershipRelated: Ownership Preview - moves and borrows in depth
Borrow with & for read-only access, &mut for exclusive mutation.
fn len(s: &String) -> usize {
s.len()
}
fn main() {
let mut text = String::from("rust");
println!("{}", len(&text));
text.push_str("ace");
println!("{text}");
}&mut or many & to the same data at a time&[T], &str) are fat pointers to contiguous sequencesRelated: References & Slices - slice syntax and bounds
matchmatch is exhaustive: every variant must be handled.
enum Status {
Ok,
Err(u16),
}
fn describe(s: Status) -> &'static str {
match s {
Status::Ok => "success",
Status::Err(code) => {
println!("error code: {code}");
"failure"
}
}
}
fn main() {
println!("{}", describe(Status::Ok));
}_ is a wildcard arm for catch-all patternscode) extract inner values from enum variantsmatch on Option/Result is the idiomatic error pathRelated: Control Flow -
if letand loops
Result for Recoverable ErrorsFunctions that can fail return Result<T, E>.
use std::fs;
fn read_config(path: &str) -> Result<String, std::io::Error> {
fs::read_to_string(path)
}
fn main() {
match read_config("config.toml") {
Ok(body) => println!("{body}"),
Err(e) => eprintln!("failed: {e}"),
}
}Ok(T) carries success; Err(E) carries failure? propagates errors in functions returning Resultpanic!, unwrap) are for unrecoverable bugsanyhowRelated: Ownership Preview - error types are enums too
Tests live in the same file or in tests/ integration directories.
pub fn double(n: i32) -> i32 {
n * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn doubles_values() {
assert_eq!(double(3), 6);
}
}#[test] marks a function for cargo testassert_eq! compares debug output on failuretests/*.rs see only the public APIRelated: Rust Fundamentals Best Practices - habits before advanced topics
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026