Rust Cheatsheet
Structs
Use this Rust reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Defining Structs
// Named-field struct struct User { username: String, email: String, sign_in_count: u64, active: bool, } // Tuple struct struct Color(i32, i32, i32); struct Point(f64, f64, f64); // Unit struct (no fields) struct AlwaysEqual;
Instantiating Structs
let user1 = User { email: String::from("alice@example.com"), username: String::from("alice"), active: true, sign_in_count: 1, }; // Field shorthand — when variable name matches field name let email = String::from("bob@example.com"); let username = String::from("bob"); let user2 = User { email, // equivalent to email: email username, active: true, sign_in_count: 0, }; // Struct update syntax — fill remaining fields from another instance let user3 = User { email: String::from("carol@example.com"), ..user1 // take remaining fields from user1 (user1 may be partially moved) }; // Tuple struct let black = Color(0, 0, 0); let origin = Point(0.0, 0.0, 0.0); let r = black.0; // access by index // Unit struct let unit = AlwaysEqual;
Accessing and Mutating Fields
let mut user = User { email: String::from("alice@example.com"), username: String::from("alice"), active: true, sign_in_count: 0, }; // Access println!("{}", user.email); println!("{}", user.username); // Mutate (entire struct must be mut) user.email = String::from("alice@new.com"); user.sign_in_count += 1;
Rust does not allow marking individual fields as
mut— the whole binding must be mutable.
impl Blocks — Methods
struct Rectangle { width: f64, height: f64, } impl Rectangle { // Associated function (no self — called as Rectangle::new()) fn new(width: f64, height: f64) -> Self { Rectangle { width, height } } fn square(size: f64) -> Self { Rectangle { width: size, height: size } } // Method — immutable borrow of self fn area(&self) -> f64 { self.width * self.height } fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) } fn is_larger_than(&self, other: &Rectangle) -> bool { self.area() > other.area() } // Mutable method fn scale(&mut self, factor: f64) { self.width *= factor; self.height *= factor; } // Consuming method fn rotated(self) -> Rectangle { Rectangle { width: self.height, height: self.width } } } let rect = Rectangle::new(10.0, 5.0); println!("Area: {}", rect.area()); // 50.0 println!("Perimeter: {}", rect.perimeter()); // 30.0 let mut r = Rectangle::new(4.0, 3.0); r.scale(2.0); // now 8.0 × 6.0 let r2 = r.rotated(); // r consumed, r2 has swapped dimensions
Multiple impl Blocks
impl Rectangle { fn area(&self) -> f64 { self.width * self.height } } // Additional impl block — allowed, useful for organizing code impl Rectangle { fn debug_print(&self) { println!("{}x{}", self.width, self.height); } }
Deriving Traits
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] struct Point { x: i32, y: i32, } let p1 = Point { x: 1, y: 2 }; let p2 = p1.clone(); println!("{:?}", p1); // Debug: Point { x: 1, y: 2 } println!("{:#?}", p1); // Pretty-print assert_eq!(p1, p2); // PartialEq let p0: Point = Point::default(); // Default: { x: 0, y: 0 } // Common derivable traits: // Debug — {:?} formatting // Clone — .clone() method // Copy — implicit copy on assignment (requires Clone) // PartialEq — == and != // Eq — full equivalence (requires PartialEq, no NaN-like values) // PartialOrd — < > <= >= (requires PartialEq) // Ord — total ordering (requires PartialOrd + Eq) // Hash — use as HashMap key (requires Eq) // Default — zero/empty value via Default::default()
Implementing Display
use std::fmt; struct Point { x: f64, y: f64 } impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } } let p = Point { x: 1.0, y: 2.5 }; println!("{}", p); // (1, 2.5) let s = p.to_string(); // to_string() is free when Display is implemented
Implementing Traits on Structs
use std::ops::{Add, Mul, Neg}; #[derive(Debug, Clone, Copy, PartialEq)] struct Vec2 { x: f64, y: f64 } impl Vec2 { fn new(x: f64, y: f64) -> Self { Vec2 { x, y } } fn dot(&self, other: &Vec2) -> f64 { self.x * other.x + self.y * other.y } fn length(&self) -> f64 { (self.x * self.x + self.y * self.y).sqrt() } } impl Add for Vec2 { type Output = Vec2; fn add(self, other: Vec2) -> Vec2 { Vec2::new(self.x + other.x, self.y + other.y) } } impl Neg for Vec2 { type Output = Vec2; fn neg(self) -> Vec2 { Vec2::new(-self.x, -self.y) } } impl Mul<f64> for Vec2 { type Output = Vec2; fn mul(self, scalar: f64) -> Vec2 { Vec2::new(self.x * scalar, self.y * scalar) } } let a = Vec2::new(1.0, 2.0); let b = Vec2::new(3.0, 4.0); let c = a + b; // Vec2 { x: 4.0, y: 6.0 }
Struct Visibility
pub struct PublicStruct { pub public_field: String, // accessible anywhere private_field: i32, // only within the module pub(crate) crate_field: bool, // accessible within the crate pub(super) super_field: f64, // accessible in parent module } // Even if the struct is pub, private fields limit construction from outside: // External code cannot do: PublicStruct { private_field: 42, ... } // Provide constructor associated functions for that: impl PublicStruct { pub fn new(s: String, n: i32) -> Self { PublicStruct { public_field: s, private_field: n, crate_field: true, super_field: 0.0, } } }
Builder Pattern
#[derive(Debug)] struct RequestBuilder { url: String, method: String, timeout: u64, headers: Vec<(String, String)>, } impl RequestBuilder { fn new(url: impl Into<String>) -> Self { RequestBuilder { url: url.into(), method: "GET".to_string(), timeout: 30, headers: Vec::new(), } } fn method(mut self, m: impl Into<String>) -> Self { self.method = m.into(); self } fn timeout(mut self, secs: u64) -> Self { self.timeout = secs; self } fn header(mut self, key: impl Into<String>, val: impl Into<String>) -> Self { self.headers.push((key.into(), val.into())); self } fn build(self) -> RequestBuilder { self } } let req = RequestBuilder::new("https://api.example.com") .method("POST") .timeout(60) .header("Content-Type", "application/json") .build();
Newtype Pattern
Wrap a type in a single-field tuple struct to create a distinct type:
struct Meters(f64); struct Kilograms(f64); fn travel(distance: Meters) { println!("Travelling {} meters", distance.0); } let m = Meters(5.0); let k = Kilograms(70.0); travel(m); // travel(k); // compile error — type safety! // Implement Display for a foreign type by wrapping it use std::fmt; struct Wrapper(Vec<String>); impl fmt::Display for Wrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{}]", self.0.join(", ")) } }
Struct Memory Layout
// Fields are laid out in declaration order (by default) // Use #[repr(C)] for C-compatible layout // Use #[repr(packed)] to remove padding // Use #[repr(align(N))] to set alignment #[repr(C)] struct CStruct { x: u8, // 1 byte y: u32, // 4 bytes (3 bytes padding before this with default repr) } // std::mem utilities use std::mem; mem::size_of::<Rectangle>() // size in bytes mem::align_of::<Rectangle>() // alignment in bytes mem::size_of_val(&rect) // size of a value