Rust: Rust Operators and Expressions
Last updated: 2026-08-26
In Rust, almost everything is an expression—including
ifandmatch.
Understanding the difference between expressions (which return a value) and statements (which do not return a value) is key to writing concise Rust code.
1. What You'll Learn
- Arithmetic Operators:
+ - * / % - Comparison Operators:
== != < > <= >= - Logical Operators:
&& || ! - Bitwise operators:
& | ^ << >> - The Difference Between Expressions and Statements
- Operator Precedence
2. The Story of a Cashier
(1) Frustration: I always make mistakes when calculating discounts
Tom is the manager of a clothing store, and every day he has to calculate various discounts:
- Buy 2 items and get 20% off; buy 3 items and get 30% off
- Save 50 on orders of 500 or more
- Members get an additional 5% off
- I miscalculated the order when combining discounts, which caused the accounts to not balance at the end of the month, resulting in a loss of 500 yuan.
"It would be great if there were a calculator that could automatically perform calculations in the correct order..."
(2) Rust's Expression Scheme
fn main() {
let price: f64 = 299.0; // A piece of clothing 299 yuan
let quantity: i32 = 3; // Bought 3 items
let is_member: bool = true; // Is a member
// Calculate all discounts with a single expression
let total = (price * quantity as f64) // Original Price
* if quantity >= 3 { 0.7 } else { 0.9 } // Volume Discount
* if is_member { 0.95 } else { 1.0 }; // Member Discounts
println!("Original Price: {:.2} yuan", price * quantity as f64);
println!("Price after discount: {:.2} yuan", total);
println!("Save: {:.2} yuan", price * quantity as f64 - total);
}
In Rust,
ifis an expression in itself and can return a value directly. This allows the discount calculation to be expressed as a single chain of expressions, eliminating the risk of errors.
3. List of Operators
graph TB
A[Rust Operators] --> B[Arithmetic: + - * / %]
A --> C[Comparison: == != < > <= >=]
A --> D[Logic: && || !]
A --> E[Bitwise Operations: & | ^ << >>]
A --> F[Assignment: = += -= *= /=]
(1) Arithmetic Operators
| Operator | Example | Description |
|---|---|---|
+ |
a + b |
Addition |
- |
a - b |
Subtraction |
* |
a * b |
Multiplication |
/ |
a / b |
Division (Integer Truncation) |
% |
a % b |
remainder |
- |
-a |
Take Negative (Unary) |
Integer division results in truncation:
5 / 2 = 2(not 2.5). To obtain a floating-point result, you need to use a floating-point type:5.0 / 2.0 = 2.5.
(2) Comparison Operators
All comparison operators return the bool type: true or false.
let a = 10;
let b = 20;
println!("{}", a == b); // false
println!("{}", a != b); // true
println!("{}", a < b); // true
(3) Logical Operators
| Operator | Name | Example | Description |
|---|---|---|---|
&& |
Logic AND | a && b |
True only if both are true (short-circuit) |
| ` | ` | Logical OR | |
! |
Logical NOT | !a |
Invert |
Short-circuit evaluation:
&&—if the left side is false, the right side is not evaluated;||—if the left side is true, the right side is not evaluated. This can be used in a "check-before-access" pattern.
(4) Bitwise Operators
| Operator | Name | Example | Description |
|---|---|---|---|
& |
Bitwise AND | a & b |
Equals 1 only if all corresponding bits are 1 |
| ` | ` | Bitwise OR | `a |
^ |
Bitwise XOR | a ^ b |
Equals 1 only if the corresponding bits are different |
<< |
Shift left | a << n |
Shift left by n bits (equivalent to multiplying by 2^n) |
>> |
Shift right | a >> n |
Shift right by n bits (equivalent to division by 2^n) |
4. Expressions and Statements
(1) Key Differences
| Concept | Definition | Example |
|---|---|---|
| Expression | Has a return value | 5 + 3 returns 8, if true { 1 } else { 0 } returns 1 |
| Statement | No return value | let x = 5; No return value, fn foo() {} No return value |
In Rust, semicolons determine whether something is an expression or a statement:
fn main() {
let y = {
let x = 3;
x + 1 // No semicolons -- This is an expression, Returns 4
}; // End of semicolon let Statement
println!("y the value: {}", y); // 4
}
(2) Block Expressions
{} The code block within the block can be an expression; if the last line does not end with a semicolon, it returns a value:
let result = {
let a = 2;
let b = 3;
a * b // No semicolons, This expression returns 6
};
5. Examples of Operators
▶ Example 1: Arithmetic Operations and Types (Difficulty ⭐)
Output:
Addition: 10 + 3 = 13
Subtraction: 10 - 3 = 7
Multiplication: 10 * 3 = 30
Integer Division: 10 / 3 = 3 (Truncation)
Floating-Point Division: 10.0 / 3.0 = 10.0
Modulo: 10 % 3 = 1
// ============================================
// Demonstration of Arithmetic Operators——Note: Truncation in integer division
// ============================================
fn main() {
let a = 10;
let b = 3;
println!("Addition: {} + {} = {}", a, b, a + b);
println!("Subtraction: {} - {} = {}", a, b, a - b);
println!("Multiplication: {} * {} = {}", a, b, a * b);
println!("Integer Division: {} / {} = {} (Truncation)", a, b, a / b);
println!("Floating-Point Division: {} / {} = {:.2}", a as f64, b as f64, a as f64 / b as f64);
println!("Modulo: {} % {} = {}", a, b, a % b);
}
Output:
Addition: 10 + 3 = 13
Subtraction: 10 - 3 = 7
Multiplication: 10 * 3 = 30
Integer Division: 10 / 3 = 3 (Truncation)
Floating-Point Division: 10 / 3 = 3.33
Modulo: 10 % 3 = 1
Output:
Available for purchase (&&): <can_buy>
asKeywords are used for type conversion.a as f64Convert the integer to a floating-point number before performing division to obtain a floating-point result.
▶ Example 2: Short-circuit evaluation of logical operations (Difficulty: ⭐⭐)
Output:
Available for purchase (&&): <can_buy>
(|| Short Circuit, The right side will not be executed): <is_ok>
This function will not be executed!
// ============================================
// Short-Circuit Evaluation of Logical Operators
// ============================================
fn main() {
let age = 17;
let has_id = true;
// && Short Circuit: If the left is false, the right side is not executed
let can_buy = age >= 18 && has_id;
println!("Available for purchase (&&): {}", can_buy); // false (Since the left side is already false)
// || Short Circuit: If the left is true, the right side is not executed
let is_ok = true || (expensive_check());
println!("(|| Short Circuit, The right side will not be executed): {}", is_ok);
}
fn expensive_check() -> bool {
println!("This function will not be executed!");
true
}
Output:
Available for purchase (&&): false
(|| Short Circuit, The right side will not be executed): true
Output:
Score: 85, Level: <grade>
Short-circuit evaluation is an important performance optimization—it places low-cost checks on the left and high-cost checks on the right to avoid unnecessary computations.
▶ Example 3: Expression Block Return Values (Difficulty ⭐⭐)
Output:
Score: 85, Level: <grade>
Result: <is_pass>
// ============================================
// Using Expression Blocks to Implement Concise Assignments with Complex Conditions
// ============================================
fn main() {
let score = 85;
let grade = {
if score >= 90 {
"A"
} else if score >= 80 {
"B"
} else if score >= 70 {
"C"
} else if score >= 60 {
"D"
} else {
"F"
}
}; // Note: The entire if-else chain is an expression, End with a semicolon let Statement
println!("Score: {}, Level: {}", score, grade);
// Alternatives to Ternary Operations: Use if Expression
let is_pass = if score >= 60 { "passed" } else { "failed" };
println!("Result: {}", is_pass);
}
Output:
User Permissions: <user_perm> (Read+Write)
Full Permissions: <full_perm> (Read+Write+Execute)
User-readable: <can_read>, Executable: <can_exec>
Remove Write Permissions: <no_write>
Toggle the execution bit: <toggled>
Red: <red>
Rust doesn't have a ternary operator (
condition ? a : b), butifis an expression in itself and can achieve the same result with better readability.
▶ Example 4: Bitwise Operations in Practice—Permission Flags and Color Mixing (Difficulty ⭐⭐)
Output:
User Permissions: <user_perm> (Read+Write)
Full Permissions: <full_perm> (Read+Write+Execute)
User-readable: <can_read>, Executable: <can_exec>
Remove Write Permissions: <no_write>
Toggle the execution bit: <toggled>
Red: <red>
Yellow (Red|Green): <yellow>
White (Red|Green|Blue): <white>
Pixel #FF8040 → R=<r>, G=<g>, B=<b>
1 << 0 = <shift_val << 0>
// ============================================
// Bitwise Operations in Practice:File Permissions and RGB Color Manipulation
// ============================================
fn main() {
let read_perm: u8 = 0b100; // 4
let write_perm: u8 = 0b010; // 2
let exec_perm: u8 = 0b001; // 1
let user_perm = read_perm | write_perm;
println!("User Permissions: {:03b} (Read+Write)", user_perm);
let full_perm = read_perm | write_perm | exec_perm;
println!("Full Permissions: {:03b} (Read+Write+Execute)", full_perm);
let can_read = (user_perm & read_perm) != 0;
let can_exec = (user_perm & exec_perm) != 0;
println!("User-readable: {}, Executable: {}", can_read, can_exec);
let no_write = user_perm & !write_perm;
println!("Remove Write Permissions: {:03b}", no_write);
let toggled = user_perm ^ exec_perm;
println!("Toggle the execution bit: {:03b}", toggled);
let red: u32 = 0xFF0000;
let green: u32 = 0x00FF00;
let blue: u32 = 0x0000FF;
let yellow = red | green;
let white = red | green | blue;
println!("\nRed: {:06X}", red);
println!("Yellow (Red|Green): {:06X}", yellow);
println!("White (Red|Green|Blue): {:06X}", white);
let pixel: u32 = 0xFF8040;
let r = (pixel >> 16) & 0xFF;
let g = (pixel >> 8) & 0xFF;
let b = pixel & 0xFF;
println!("\nPixel #FF8040 → R={}, G={}, B={}", r, g, b);
let shift_val: u8 = 1;
println!("\n1 << 0 = {}", shift_val << 0);
println!("1 << 1 = {}", shift_val << 1);
println!("1 << 2 = {}", shift_val << 2);
println!("1 << 3 = {}", shift_val << 3);
}
Output:
User Permissions: 110 (Read+Write)
Full Permissions: 111 (Read+Write+Execute)
User-readable: true, Executable: false
Remove Write Permissions: 100
Toggle the execution bit: 111
Red: FF0000
Yellow (Red|Green): FFFF00
White (Red|Green|Blue): FFFFFF
Pixel #FF8040 → R=255, G=128, B=64
1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
Bitwise operations are extremely common in system programming: for permission management, use
|to merge,&to check, and& !to remove; for colors, use|to blend and>>+&to extract channels;<<is equivalent to multiplying by a power of 2.
▶ Example 5: Operator Precedence and Compound Expressions (Difficulty ⭐⭐⭐)
Output:
=== Operator Precedence ===
2 + 3 * 4 = 14 (Multiply First, Then Add)
(2 + 3) * 4 = <b> (Parentheses Take Precedence)
10 - 6 / 2 = 7.0 (Multiply First, Then Subtract)
true && false || true = <d> (&& Take precedence over ||)
true || false && false = <e> (&& Take precedence over ||)
=== Compound Assignment Operator ===
score += 20 → 100
score -= 30 → 100
score *= 2 → 100
score /= 7 → 100
score %= 3 → 100
=== Chain Comparison(Using logical operators)===
x=50, in [0,100]: <in_range>, Out of range: <out_range>
Both passed: <both_passed>, Someone excellent: <any_excellent>
// ============================================
// Operator Precedence in Practice + Compound Assignment Operator
// ============================================
fn main() {
println!("=== Operator Precedence ===");
let a = 2 + 3 * 4;
println!("2 + 3 * 4 = {} (Multiply First, Then Add)", a);
let b = (2 + 3) * 4;
println!("(2 + 3) * 4 = {} (Parentheses Take Precedence)", b);
let c = 10 - 6 / 2;
println!("10 - 6 / 2 = {} (Multiply First, Then Subtract)", c);
let d = true && false || true;
println!("true && false || true = {} (&& Take precedence over ||)", d);
let e = true || false && false;
println!("true || false && false = {} (&& Take precedence over ||)", e);
println!("\n=== Compound Assignment Operator ===");
let mut score: i32 = 100;
score += 20;
println!("score += 20 → {}", score);
score -= 30;
println!("score -= 30 → {}", score);
score *= 2;
println!("score *= 2 → {}", score);
score /= 7;
println!("score /= 7 → {}", score);
score %= 3;
println!("score %= 3 → {}", score);
println!("\n=== Chain Comparison(Using logical operators)===");
let x = 50;
let in_range = x >= 0 && x <= 100;
let out_range = x < 0 || x > 100;
println!("x={}, in [0,100]: {}, Out of range: {}", x, in_range, out_range);
let charlie_score = 75;
let bob_score = 88;
let both_passed = charlie_score >= 60 && bob_score >= 60;
let any_excellent = charlie_score >= 90 || bob_score >= 90;
println!("Both passed: {}, Someone excellent: {}", both_passed, any_excellent);
}
Output:
=== Operator Precedence ===
2 + 3 * 4 = 14 (Multiply First, Then Add)
(2 + 3) * 4 = 20 (Parentheses Take Precedence)
10 - 6 / 2 = 7 (Multiply First, Then Subtract)
true && false || true = true (&& Take precedence over ||)
true || false && false = true (&& Take precedence over ||)
=== Compound Assignment Operator ===
score += 20 → 120
score -= 30 → 90
score *= 2 → 180
score /= 7 → 25
score %= 3 → 1
=== Chain Comparison(Using logical operators)===
x=50, in [0,100]: true, Out of range: false
Both passed: true, Someone excellent: false
Operator precedence, from highest to lowest:
* / %→+ -→ comparison operators →&&→||. When in doubt, use parentheses; code readability is more important than "conciseness."
❓ FAQ
as?as silently truncates data without reporting an error.📖 Summary
- Rust has four types of operators: arithmetic, comparison, logical, and bitwise; most of them are consistent with those in other languages.
- Integer division results in truncation; use
asto convert to floating-point division - The logical operators
&&and||exhibit short-circuit evaluation behavior - Expressions have return values, while statements do not—the semicolon makes all the difference.
ifis an expression in itself and can be used as a substitute for the ternary operator in other languages Rust does not have++/--, use+= 1/-= 1instead.
📝 Exercises
- Difficulty ⭐: Write a program that uses the
asconversion to converti32-type5and2tof64, and outputs5 / 2 = 2.5. - Difficulty ⭐⭐: Define a variable
x = 5, use an expression block{ x + 1 }to assign a value toy, and determine whetherxis still accessible outside the expression block. - Difficulty ⭐⭐⭐: Implement a function
fn is_even(n: i32) -> boolusing bitwise operators, where you must use&bitwise operations (not%) to determine parity.