Chapter 10: Rust Operators
Rust Operators
Operators are the “verbs” of programming — they tell the computer what to do with values (add, compare, check truth, etc.). Rust’s operators are very similar to C/C++/Java/Python, but with some Rust-specific twists (like safe overflow behavior in debug mode, the ? operator for errors, and powerful overloading via traits).
Today I’ll explain everything like your patient teacher: slowly, category by category, with lots of copy-paste examples you can run in your project, real Hyderabad-flavored analogies, precedence rules (very important!), and tips on what surprises beginners.
1. Categories of Operators in Rust
Rust groups operators into these families:
- Arithmetic (+ – * / %)
- Bitwise (& | ^ ~ << >>)
- Comparison (== != > < >= <=)
- Logical (&& || !)
- Assignment (= += -= *= /= %= &= |= ^= <<= >>=)
- Compound assignment (like above)
- Unary (- ! * & &mut)
- Borrow / dereference (* &)
- Range (.. ..=)
- Error propagation (?)
- Type cast (as)
- Others (indexing [], field ., method call, path ::)
Most are overloadable via traits (std::ops::*) — you can make your own types work with +, *, etc.
2. Arithmetic Operators (Most Common)
Work on numbers (i32, f64, etc.)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
fn main() { let a: i32 = 15; let b: i32 = 4; println!("Addition: {} + {} = {}", a, b, a + b); // 19 println!("Subtraction: {} - {} = {}", a, b, a - b); // 11 println!("Multiplication: {} * {} = {}", a, b, a * b); // 60 println!("Division: {} / {} = {}", a, b, a / b); // 3 (integer division!) println!("Remainder: {} % {} = {}", a, b, a % b); // 3 let pi = 3.14159_f64; println!("Float div: {:.4}", pi / 2.0); // 1.5708 } |
Important notes:
- Integer division truncates toward zero (15 / 4 = 3)
- In debug mode: overflow panics (let x = 255u8 + 1; → panic!)
- In release mode: wraps around (255u8 + 1 = 0)
- Use checked_add, wrapping_add, saturating_add for control
3. Comparison & Logical Operators
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fn main() { let temp = 35; let is_hot = temp > 32; // true let is_extreme = temp >= 40 || temp <= 10; println!("Is hot? {}", is_hot); // true println!("Extreme? {}", is_extreme); // false let raining = false; if is_hot && !raining { println!("Perfect Hyderabad summer day! ☀️"); } // Equality works on many types println!("Equal? {}", "biryani" == "biryani"); // true } |
- && and || are short-circuit (right side skipped if not needed)
- ! = logical NOT
4. Bitwise Operators (Low-level magic)
Used for flags, masks, binary ops.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
fn main() { let flags: u8 = 0b0000_1010; // 10 in decimal println!("AND: {:08b}", flags & 0b0000_1100); // 00001000 println!("OR: {:08b}", flags | 0b0000_0101); // 00001111 println!("XOR: {:08b}", flags ^ 0b0000_1111); // 00010101 println!("NOT: {:08b}", !flags); // 11110101 (inverts bits) println!("Left shift: {}", 5 << 2); // 20 (5 * 4) println!("Right shift: {}", 20 >> 2); // 5 } |
Great for bit flags (permissions, colors, etc.).
5. Assignment & Compound Assignment
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
fn main() { let mut score = 100; score += 50; // score = score + 50 score -= 20; score *= 2; score /= 4; println!("Final score: {}", score); // 65 } |
All arithmetic + bitwise have compound versions (+=, &=, etc.).
6. Unary Operators
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fn main() { let positive = 42; println!("Negate: {}", -positive); // -42 let is_true = true; println!("NOT: {}", !is_true); // false let s = String::from("hello"); let ref_s = &s; // borrow println!("Length via ref: {}", ref_s.len()); let num = 10; let ptr = &num as *const i32; // raw pointer (unsafe territory) } |
- – unary minus
- ! logical/bitwise NOT
- & immutable borrow
- &mut mutable borrow
- * dereference (for references/smart pointers)
7. Special Rust Operators (These Make Rust Unique)
A. Range operators .. and ..=
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for i in 1..5 { // 1,2,3,4 println!("i = {}", i); } for i in 1..=5 { // 1 to 5 inclusive println!("Inclusive: {}", i); } let slice = &vec![10,20,30,40][2..]; // from index 2 to end |
B. The famous ? operator (error propagation)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
use std::fs::File; fn read_file() -> Result<String, std::io::Error> { let mut file = File::open("hello.txt")?; // if error → early return let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) } |
? = “try this, if error bubble it up”
C. as for type casting
|
0 1 2 3 4 5 6 7 |
let big: i64 = 1_000_000; let small: i32 = big as i32; // explicit cast |
8. Operator Precedence (Very Important — Order of Operations)
Rust follows a clear precedence table (from highest to lowest — official reference style):
- Paths, method calls, field access .
- Function calls, indexing []
- ?
- Unary – ! * & &mut
- as (casting)
- * / % (multiply, divide, remainder)
- + – (add, subtract)
- << >> (shifts)
- & (bitwise AND)
- ^ (bitwise XOR)
- (bitwise OR)
- == != < > <= >= (comparisons)
- && (logical AND)
- || (logical OR)
- Assignment = += -= etc.
Rule: Higher precedence first. Same level → left-to-right (except assignment right-to-left).
Example:
|
0 1 2 3 4 5 6 7 |
let result = 5 + 3 * 4; // 3*4 first → 5 + 12 = 17 let bool_result = true || false && true; // && first → false && true = false → true || false = true |
Always use parentheses () when in doubt — makes code clearer!
Quick Practice Project
Add this to your main.rs:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
fn main() { let a = 10; let b = 3; println!("{} + {} = {}", a, b, a + b); println!("{} / {} = {} (integer)", a, b, a / b); println!("{} % {} = {}", a, b, a % b); let hot = 35 > 32 && !(true || false); println!("Is hot && not (rain or storm)? {}", hot); for i in 1..=5 { print!("{} ", i); } println!(); } |
Run → experiment! Change numbers, add parentheses, see what breaks.
Teacher Summary
Rust operators feel familiar but safer:
- Arithmetic like school math (but watch integer division & overflow)
- Logical & comparison same as most languages
- Bitwise for power users
- ? = Rust’s gift for clean error handling
- Precedence same as C-family → parentheses save headaches
Next ready?
- Control flow (if, match, loops)?
- Functions + how operators work in them?
- Or strings & formatting (where + and format! use operators)?
Just tell me — class continues! 🦀🚀
