Basics
Updated: November 24, 2025
Learn the basic components that make up the Rust language.
Table of Contents
- Borrowing
- Concurrency
- Enums
- Errors
- Functions
- Generics
- Macros
- Ownership
- Structs
- Syntax
- Testing
- Types
- Variables
Borrowing
- References:
&for immutable,&mutfor mutable - Borrowing allows multiple immutable references or one mutable
- Lifetimes ensure references don’t outlive data
- Deref coercion automatically converts references
let s = String::from("hello");
let r1 = &s; // immutable borrow
let r2 = &s; // another immutable borrow
let r3 = &mut s; // mutable borrow (would fail if r1/r2 exist)
Concurrency
- Threads:
std::thread::spawnfor concurrent execution - Channels:
mpscfor message passing between threads - Async:
async fn,awaitfor asynchronous programming - Mutexes and Arcs for shared state
use std::thread;
let handle = thread::spawn(|| {
println!("Hello from a thread!");
});
handle.join().unwrap();
Enums
- Define variants with
enum, can hold data - Use
matchto handle different variants - Common enums:
Option<T>,Result<T, E>
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
match home {
IpAddr::V4(a, b, c, d) => println!("{}.{}.{}.{}", a, b, c, d),
IpAddr::V6(addr) => println!("{}", addr),
}
Errors
panic!macro for unrecoverable errorsResult<T, E>for recoverable errorsunwrap()andexpect()for quick handling?operator propagates errors
use std::fs::File;
fn read_file() -> Result<String, std::io::Error> {
let f = File::open("hello.txt")?;
Ok(String::from("file contents"))
}
Functions
- Define with
fn, specify return type with-> - Parameters with types, body in braces
- Closures: anonymous functions with
|args| body - Higher-order functions accept/return functions
fn add(x: i32, y: i32) -> i32 {
x + y
}
let add_closure = |x: i32, y: i32| -> i32 { x + y };
let result = add_closure(1, 2);
Generics
<T>for type parameters in functions and structs- Traits constrain generic types
- Monomorphization generates specific code at compile time
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
Macros
- Declarative macros:
macro_rules! - Procedural macros: custom derive, attribute, function-like
- Used for code generation and metaprogramming
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
let v = vec![1, 2, 3];
Ownership
- Each value has an owner, only one at a time
- Assignment moves ownership, unless type implements
Copy - Functions take ownership or borrow parameters
Droptrait runs when value goes out of scope
let s1 = String::from("hello");
let s2 = s1; // s1 moved to s2, s1 invalid
let s3 = s2.clone(); // explicit copy
fn take_ownership(s: String) { /* s owned here */ }
fn borrow(s: &String) { /* s borrowed here */ }
Structs
- Define with
struct, fields with types implblocks for methods and associated functions- Tuple structs and unit structs
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
Syntax
- Rust uses snake_case for variables and functions
- Lines without a
;are expressions that return a value letdeclares variables,constfor compile-time constants- Functions use
fnkeyword, parameters in parentheses
let x = 5; // statement
let y = x + 1; // expression
fn add(a: i32, b: i32) -> i32 { a + b } // function
Testing
#[test]attribute marks test functionsassert!,assert_eq!,assert_ne!for assertions- Run tests with
cargo test - Integration tests in
tests/directory
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
#[test]
#[should_panic]
fn test_panic() {
panic!("This test should panic");
}
}
Types
- Primitive types:
bool,char,i8/i16/i32/i64/i128,u8/u16/u32/u64/u128,f32/f64 Stringfor owned strings,&strfor string slices- Arrays:
[T; N], vectors:Vec<T> - Structs:
struct Name { field: Type } - Enums:
enum Name { Variant1, Variant2(Type) } - Option:
Option<T>for nullable values, Result:Result<T, E>for error handling
let s: String = String::from("hello");
let arr: [i32; 3] = [1, 2, 3];
struct Point { x: f64, y: f64 }
enum Message { Quit, Move { x: i32, y: i32 } }
Variables
letbinds immutable variables,let mutfor mutable- Shadowing allows redeclaring with same name
constfor compile-time constants,staticfor global variables- Type annotation optional due to inference
let x = 5; // immutable
let mut y = 5; // mutable
y = 6;
let y = y + 1; // shadowing
const MAX_POINTS: u32 = 100_000;
static mut COUNTER: u32 = 0;