RUST PROGRAMMING
Complete Notes — Memory Safety, Ownership & Systems Programming
Rust is a systems programming language focused on three goals: safety, speed, and concurrency. It
achieves memory safety without a garbage collector, making it ideal for performance-critical applications,
WebAssembly, embedded systems, and OS development.
1. Getting Started with Rust
1.1 Installation & Hello World
# Install via rustup
curl --proto '=https' --tlsv1.2 -sSf [Link] | sh
# Create a project
cargo new my_project
cd my_project
cargo run
// src/[Link]
fn main() {
println!("Hello, Rust!");
println!("2 + 2 = {}", 2 + 2);
}
1.2 Variables & Mutability
fn main() {
let x = 5; // immutable by default
let mut y = 10; // mutable
y += 5;
println!("{} {}", x, y); // 5 15
let z: f64 = 3.14; // explicit type annotation
let s: &str; = "hello"; // string slice
let owned = String::from("world"); // owned String
}
Note: In Rust, variables are immutable by default. Use mut keyword to allow mutation.
2. Ownership — Rust's Core Concept
Ownership is Rust's most unique feature. Every value has a single owner; when the owner goes out of
scope, the value is dropped. This eliminates memory leaks and dangling pointers without a GC.
2.1 Ownership Rules
• Each value in Rust has exactly one owner variable
• When the owner goes out of scope, the value is dropped
• There can only be one owner at a time (no shared mutation)
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2
// println!("{}", s1); // ERROR: s1 was moved!
println!("{}", s2); // OK
let s3 = [Link](); // deep copy — both valid
println!("{} {}", s2, s3);
}
2.2 Borrowing & References
fn length(s: &String;) -> usize {
[Link]() // borrows s, does not take ownership
}
fn main() {
let s = String::from("hello world");
let len = length(&s;); // pass reference
println!("'{}' has {} chars", s, len); // s still valid
}
Note: References allow you to refer to a value without taking ownership. This is called borrowing.
3. Data Types & Structs
3.1 Primitive Types
• Integers: i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize
• Floats: f32, f64
• Boolean: bool (true / false)
• Character: char (4-byte Unicode scalar value)
• Tuples: (i32, f64, bool)
• Arrays: [i32; 5] — fixed-length, same type
3.2 Structs
struct Point {
x: f64,
y: f64,
}
impl Point {
fn new(x: f64, y: f64) -> Self {
Point { x, y }
}
fn distance(&self;, other: &Point;) -> f64 {
let dx = self.x - other.x;
let dy = self.y - other.y;
(dx*dx + dy*dy).sqrt()
}
}
let p1 = Point::new(0.0, 0.0);
let p2 = Point::new(3.0, 4.0);
println!("Distance: {}", [Link](&p2;)); // 5
4. Enums & Pattern Matching
enum Shape {
Circle(f64),
Rectangle(f64, f64),
Triangle(f64, f64, f64),
}
impl Shape {
fn area(&self;) -> f64 {
match self {
Shape::Circle(r) => std::f64::consts::PI * r * r,
Shape::Rectangle(w, h) => w * h,
Shape::Triangle(a,b,c) => {
let s = (a + b + c) / 2.0;
(s*(s-a)*(s-b)*(s-c)).sqrt()
}
}
}
}
let c = Shape::Circle(5.0);
println!("Area: {:.2}", [Link]());
4.1 Option & Result
// Option — value may or may not exist
fn divide(a: f64, b: f64) -> Option {
if b == 0.0 { None } else { Some(a / b) }
}
match divide(10.0, 2.0) {
Some(v) => println!("Result: {}", v),
None => println!("Cannot divide by zero"),
}
// Result — success or failure
use std::fs;
let content = fs::read_to_string("[Link]");
match content {
Ok(text) => println!("{}", text),
Err(e) => println!("Error: {}", e),
}
5. Control Flow
// if let — concise pattern matching
let opt = Some(42);
if let Some(val) = opt {
println!("Got: {}", val);
}
// while let
let mut stack = vec![1, 2, 3];
while let Some(top) = [Link]() {
println!("{}", top);
}
// loop with return value
let result = loop {
let x = expensive_computation();
if x > 100 { break x; }
};
// Ranges
for i in 1..=5 {
print!("{} ", i); // 1 2 3 4 5
}
6. Collections & Iterators
// Vec
let mut nums: Vec = vec![3, 1, 4, 1, 5, 9];
[Link](2);
[Link]();
println!("{:?}", nums);
// HashMap
use std::collections::HashMap;
let mut scores: HashMap = HashMap::new();
[Link](String::from("Alice"), 95);
[Link](String::from("Bob"), 87);
for (name, score) in &scores; {
println!("{}: {}", name, score);
}
6.1 Iterator Chaining
let nums = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result: Vec = [Link]()
.filter(|&&x;| x % 2 == 0)
.map(|&x;| x * x)
.collect();
println!("{:?}", result); // [4, 16, 36, 64, 100]
let total: i32 = [Link]().sum();
println!("Sum: {}", total); // 55
7. Traits & Generics
use std::fmt;
trait Describable {
fn describe(&self;) -> String;
fn summary(&self;) -> String {
format!("Summary: {}", [Link]()) // default impl
}
}
struct Book {
title: String,
author: String,
}
impl Describable for Book {
fn describe(&self;) -> String {
format!("'{}' by {}", [Link], [Link])
}
}
// Generic function with trait bound
fn print_desc(item: &T;) {
println!("{}", [Link]());
}
7.1 Lifetimes
// Lifetime annotation ensures references stay valid
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if [Link]() > [Link]() { s1 } else { s2 }
}
Note: Lifetimes are Rust's way of ensuring all borrows are valid. The compiler catches errors at compile time.
8. Concurrency & Cargo
use std::thread;
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..5 {
let c = Arc::clone(&counter;);
let h = thread::spawn(move || {
let mut num = [Link]().unwrap();
*num += 1;
});
[Link](h);
}
for h in handles { [Link]().unwrap(); }
println!("Counter: {}", *[Link]().unwrap()); // 5
8.1 Cargo — Rust's Build Tool
• cargo new — create a new project
• cargo build — compile the project
• cargo run — build and execute
• cargo test — run all tests
• cargo add — add a dependency
• [Link] — Rust's package registry
Rust consistently ranks as the most loved programming language in Stack Overflow surveys. Its
zero-cost abstractions, fearless concurrency, and compile-time safety checks make it the future of
systems programming.