0% found this document useful (0 votes)
3 views9 pages

49 Rust Programming

Rust is a systems programming language emphasizing memory safety, concurrency, and performance through its ownership system, which eliminates the need for garbage collection. It features a unique approach to error handling, traits for interface definition, and supports concurrency with tools like threads and channels. Rust's package manager, Cargo, simplifies project management, making it suitable for various domains such as systems programming, web development, and game engines.

Uploaded by

romanovskijv508
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views9 pages

49 Rust Programming

Rust is a systems programming language emphasizing memory safety, concurrency, and performance through its ownership system, which eliminates the need for garbage collection. It features a unique approach to error handling, traits for interface definition, and supports concurrency with tools like threads and channels. Rust's package manager, Cargo, simplifies project management, making it suitable for various domains such as systems programming, web development, and game engines.

Uploaded by

romanovskijv508
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Rust Programming

Systems programming with memory safety and zero-cost abstractions

IT & Tech Reports | Class IM24A | 2026

1. Why Rust?
Rust is a systems programming language focused on memory safety, concurrency, and performance. It
achieves memory safety without a garbage collector through its ownership system — a set of rules
checked at compile time. Rust has been the most loved programming language on Stack Overflow
Developer Surveys for 9 consecutive years (2016-2024).

Feature C/C++ Go Rust

Memory safety Manual (undefined behaviour


GC (pauses)
risk) Compile-time (no GC, no bugs)

Performance Native Near-native Native (zero-cost abstractions)

Concurrency Unsafe (data races possible)


Goroutines + GC Fearless (compiler prevents races)

Build time Fast Fast Slow (complex type system)

Error handling Return codes / exceptions


error interface Result<T,E> — explicit

Package manager None (vcpkg, conan) go modules Cargo (excellent)

2. Ownership, Borrowing, and Lifetimes


The ownership system is Rust's most unique feature. Three rules: (1) every value has an owner; (2)
there can only be one owner at a time; (3) when the owner goes out of scope, the value is dropped
(memory freed automatically).

fn main() {
// Ownership: s1 owns the String
let s1 = String::from("hello");

// MOVE: ownership transferred to s2


let s2 = s1;
// println!("{}", s1); // compile error: s1 was moved!

// CLONE: deep copy if you need both


let s3 = [Link]();
println!("s2={s2}, s3={s3}"); // both valid

// Stack types (Copy trait) are copied, not moved


let x = 5;
let y = x;
println!("{x} {y}"); // both valid — integers implement Copy

// BORROWING: borrow without taking ownership


let len = calculate_length(&s3;); // pass reference
println!("'{s3}' has length {len}"); // s3 still valid

// MUTABLE BORROW: only one at a time


let mut s = String::from("hello");
let r1 = &s; // immutable borrow
let r2 = &s; // second immutable borrow — OK
println!("{r1} {r2}");
// r1 and r2 no longer used here
let r3 = &mut; s; // mutable borrow — OK (r1,r2 no longer active)
r3.push_str(", world");
}

fn calculate_length(s: &String;) -> usize { // s is a reference


[Link]()
} // s goes out of scope but does NOT own the data — nothing dropped

3. Structs, Enums, and Pattern Matching


// Struct with methods
#[derive(Debug, Clone)]
struct Student {
name: String,
score: f32,
class: String,
}

impl Student {
// Associated function (like static method)
fn new(name: &str;, score: f32, class: &str;) -> Self {
Student {
name: name.to_owned(),
score,
class: class.to_owned(),
}
}

// Method — takes &self; (immutable borrow)


fn grade(&self;) -> &str; {
match [Link] {
s if s >= 5.5 => "Excellent",
s if s >= 4.0 => "Pass",
_ => "Fail",
}
}

fn is_passing(&self;) -> bool { [Link] >= 4.0 }


}

// Enum with data — Rust enums are sum types (algebraic data types)
#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
Triangle(f64, f64, f64), // sides
}

impl Shape {
fn area(&self;) -> f64 {
match self {
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
Shape::Rectangle { width, height } => width * height,
Shape::Triangle(a, b, c) => {
let s = (a + b + c) / 2.0;
(s * (s-a) * (s-b) * (s-c)).sqrt()
}
}
}
}

fn main() {
let mut students = vec![
Student::new("Ivan", 5.8, "IM24A"),
Student::new("Anna", 4.2, "IM24A"),
Student::new("Bob", 3.5, "IM24B"),
];

// Pattern matching with if let


if let Some(top) = [Link]().max_by(|a,b| [Link].partial_cmp(&[Link];).unwrap())
{
println!("Top student: {} ({})", [Link], [Link]);
}

// Filter and collect


let passing: Vec<&Student;> = [Link]().filter(|s| s.is_passing()).collect();
println!("Passing: {}", [Link]());
}

4. Error Handling with Result and Option


use std::fs::File;
use std::io::{self, BufRead};
use std::num::ParseIntError;

// Custom error type


#[derive(Debug)]
enum AppError {
Io(io::Error),
Parse(ParseIntError),
NotFound(String),
}

impl std::fmt::Display for AppError {


fn fmt(&self;, f: &mut; std::fmt::Formatter) -> std::fmt::Result {
match self {
AppError::Io(e) => write!(f, "IO error: {e}"),
AppError::Parse(e) => write!(f, "Parse error: {e}"),
AppError::NotFound(s) => write!(f, "Not found: {s}"),
}
}
}

impl From for AppError { fn from(e: io::Error) -> Self { AppError::Io(e) } }


impl From for AppError { fn from(e: ParseIntError) -> Self { AppError::Parse(e) } }

// ? operator propagates errors automatically


fn read_score(path: &str;) -> Result {
let file = File::open(path)?; // io::Error -> AppError::Io
let line = io::BufReader::new(file)
.lines()
.next()
.ok_or(AppError::NotFound("empty file".into()))??;
let score: i32 = [Link]().parse()?; // ParseIntError -> AppError::Parse
Ok(score)
}

fn main() {
match read_score("[Link]") {
Ok(score) => println!("Score: {score}"),
Err(e) => eprintln!("Error: {e}"),
}

// Option — value that might be absent


let names = vec!["Ivan", "Anna", "Bob"];
let found: Option<&&str;> = [Link]().find(|&&n;| n.starts_with('A'));
let name = found.unwrap_or(&"unknown"); // safe unwrap with default
println!("Found: {name}");

// Chaining Option
let score: Option = Some("5.8").and_then(|s| [Link]().ok());
let doubled = [Link](|s| s * 2.0).unwrap_or(0.0);
}

5. Traits — Rust's Interface System


// Trait definition
trait Printable {
fn print(&self;);
fn summary(&self;) -> String { format!("{:?}", self as *const Self) } // default impl
}

// Trait with generic bound


fn print_all(items: &[T]) {
for item in items { [Link](); }
}

// Multiple bounds
fn debug_and_print(item: &T;) {
println!("{:?}", item);
[Link]();
}

// impl Trait syntax (simpler for return types)


fn make_printable(name: &str;) -> impl Printable {
struct Named(String);
impl Printable for Named {
fn print(&self;) { println!("Named: {}", self.0); }
}
Named(name.to_owned())
}

// Common standard traits


// Display — for user-facing formatting (println!("{}", x))
// Debug — for debug formatting (println!("{:?}", x)) — derive with #[derive(Debug)]
// Clone — explicit deep copy — derive with #[derive(Clone)]
// Copy — implicit bitwise copy (integers, bools, tuples of Copy types)
// PartialEq — == and != operators
// Ord — total ordering (sorting)
// Iterator — enables for loops and iterator adapters
// From / Into — type conversions
// Default — zero/empty value (String::default() = "")

6. Closures and Iterators


fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Closures: anonymous functions that capture their environment


let threshold = 5;
let is_big = |x: &i32;| *x > threshold; // captures threshold

// Iterator adapters (lazy — no computation until collected)


let result: Vec = [Link]()
.filter(|&&x;| x % 2 == 0) // keep evens: [2,4,6,8,10]
.map(|&x;| x * x) // square: [4,16,36,64,100]
.filter(is_big) // > 5: [16,36,64,100]
.take(3) // first 3: [16,36,64]
.collect();

println!("{result:?}"); // [16, 36, 64]

// fold — like reduce


let sum: i32 = (1..=100).fold(0, |acc, x| acc + x); // 5050

// flatten
let nested = vec![vec![1,2], vec![3,4], vec![5,6]];
let flat: Vec = nested.into_iter().flatten().collect();

// zip
let names = vec!["Ivan", "Anna"];
let scores = vec![5.8, 4.2];
let pairs: Vec<_> = [Link]().zip([Link]()).collect();
// Custom iterator
struct Counter { count: u32, max: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut; self) -> Option {
if [Link] < [Link] {
[Link] += 1;
Some([Link])
} else { None }
}
}
let sum: u32 = Counter { count: 0, max: 5 }.sum(); // 15
}

7. Concurrency — Fearless Multithreading


use std::thread;
use std::sync::{Arc, Mutex, mpsc};

// Thread spawning
let handle = thread::spawn(|| {
println!("Hello from thread {:?}", thread::current().id());
});
[Link]().unwrap();

// Sharing data: Arc>


let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
let counter = Arc::clone(&counter;); // clone the Arc (increments ref count)
let h = thread::spawn(move || {
let mut num = [Link]().unwrap();
*num += 1;
});
[Link](h);
}
for h in handles { [Link]().unwrap(); }
println!("Counter: {}", *[Link]().unwrap()); // 10

// Message passing with channels


let (tx, rx) = mpsc::channel::();

let tx2 = [Link]();


thread::spawn(move || { [Link]("Hello from thread 1".to_owned()).unwrap(); });
thread::spawn(move || { [Link]("Hello from thread 2".to_owned()).unwrap(); });

for msg in [Link]().take(2) {


println!("Received: {msg}");
}

// Async Rust with tokio


use tokio;
#[tokio::main]
async fn main_async() {
let a = tokio::spawn(async { fetch_data("url1").await });
let b = tokio::spawn(async { fetch_data("url2").await });
let (ra, rb) = tokio::join!(a, b);
}

8. Common Rust Patterns and Idioms


// Builder pattern
#[derive(Debug)]
struct Config {
host: String,
port: u16,
max_connections: usize,
}

struct ConfigBuilder {
host: String,
port: u16,
max_connections: usize,
}

impl ConfigBuilder {
fn new() -> Self {
Self { host: "localhost".into(), port: 8080, max_connections: 100 }
}
fn host(mut self, host: &str;) -> Self { [Link] = [Link](); self }
fn port(mut self, port: u16) -> Self { [Link] = port; self }
fn max_conn(mut self, n: usize) -> Self { self.max_connections = n; self }
fn build(self) -> Config {
Config { host: [Link], port: [Link], max_connections: self.max_connections }
}
}

let config = ConfigBuilder::new()


.host("[Link]")
.port(3000)
.max_conn(200)
.build();

// Newtype pattern — type safety without runtime cost


struct Metres(f64);
struct Seconds(f64);
fn speed(distance: Metres, time: Seconds) -> f64 {
distance.0 / time.0 // compiler prevents mixing up units
}

// Type state pattern — enforce protocol at compile time


struct Locked;
struct Unlocked;
struct Safe { contents: String, _state: std::marker::PhantomData }
impl Safe {
fn unlock(self, _pin: &str;) -> Safe {
Safe { contents: [Link], _state: std::marker::PhantomData }
}
}
impl Safe {
fn retrieve(&self;) -> &str; { &[Link]; }
fn lock(self) -> Safe {
Safe { contents: [Link], _state: std::marker::PhantomData }
}
}

9. Cargo — Rust's Build System and Package Manager


# Create new project
cargo new my-project # binary
cargo new my-lib --lib # library

# [Link] — project manifest


[package]
name = "my-project"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1"

[dev-dependencies]
criterion = "0.5"

# Common cargo commands


cargo build # debug build
cargo build --release # optimised build
cargo run # build + run
cargo test # run all tests
cargo test -- --nocapture # show println! in tests
cargo check # fast type check (no code gen)
cargo clippy # linter — more warnings than rustc
cargo fmt # format code (rustfmt)
cargo doc --open # generate and open documentation
cargo add serde # add dependency
cargo update # update [Link]
cargo publish # publish to [Link]

10. Where Rust Excels


Domain Why Rust? Examples

Systems programming No GC, no overhead, full control Linux kernel modules, device drivers

WebAssembly Compiles to small, fast WASM bundles


Figma, Cloudflare Workers, game engines
Domain Why Rust? Examples

CLI tools Fast startup, static binary ripgrep, fd, bat, exa, starship prompt

Networking Async tokio runtime, zero-copy axum web framework, quinn QUIC

Embedded no_std support, tiny binary size RTOS, IoT firmware, automotive

Game engines Performance + safety Bevy, Fyrox

Cryptography Timing-safe operations, no memoryrustls


bugs TLS, ring crypto

Data engineering Speed comparable to C Polars (faster than pandas), Apache Arrow

You might also like