002 - Basic Syntax and Structure
Welcome to syntax essentials. This lesson compares the Rust basics you use every day with equivalent Python constructs.
Why this matters for Python developers
You already know how to model logic. The main shift is Rust’s explicit typing and immutability-by-default.
Learning goals
By the end of this lesson, you should be able to:
- Write functions with explicit parameter and return types.
- Use mutable/immutable bindings intentionally.
- Read and write basic control flow (
if,for,while).
Concepts in 5 minutes
fndefines functions.letintroduces bindings, immutable by default.ifis an expression in Rust.- Braces define blocks; indentation is stylistic, not semantic.
1. Defining Functions
In Python, functions are defined with def, and you have the freedom of not explicitly defining types for parameters or return values:
def add(x, y):
return x + y
In Rust, functions are defined using the fn keyword. Unlike Python, Rust enforces explicit type annotations for both parameters and return values:
fn add(x: i32, y: i32) -> i32 {
x + y
}
In this Rust example, the types of x and y are explicitly declared as i32, which is a 32-bit integer, and the return type is also specified after the -> symbol. Rust’s strict type system ensures safety and performance at compile time, something Python typically handles dynamically at runtime.
Key differences
- Type annotations: Rust requires type annotations for both parameters and return types, whereas Python is dynamically typed and doesn’t require explicit types.
- Return values: In Rust, the return type is declared after the arrow (
->). Additionally, Rust doesn’t use thereturnkeyword if the last expression in the function is the return value. Python, on the other hand, always usesreturn.
2. Variables and Mutability
In Python, variables are mutable by default:
x = 10
x = x + 5
In Rust, variables are immutable by default. If you want to make a variable mutable, you have to explicitly declare it using the mut keyword:
let mut x = 10;
x = x + 5;
Key differences
- Immutability: In Rust, variables are immutable by default for safety reasons, while in Python, variables can be reassigned freely.
- Explicit mutability: Rust forces you to explicitly declare variables as mutable (
mut) if you plan to change their values.
3. Control Flow: if Statements
Python and Rust both use if statements for conditionals, but there are some differences in syntax and flexibility.
Python:
x = 10
if x > 5:
print("x is greater than 5")
else:
print("x is less than or equal to 5")
Rust:
let x = 10;
if x > 5 {
println!("x is greater than 5");
} else {
println!("x is less than or equal to 5");
}
Key differences
- Parentheses: In Rust, the condition doesn’t need parentheses (similar to Python), but it’s required to use curly braces
{}around blocks of code. - Block structure: In Rust, control flow structures always require curly braces, while in Python, indentation is used to define blocks.
4. Loops: for and while
Python’s for loop iterates over sequences like lists or ranges, while Rust’s for loop works similarly but is often paired with iterators.
Python:
for i in range(5):
print(i)
Rust:
for i in 0..5 {
println!("{}", i);
}
Key differences
- Ranges: In Python,
range(5)generates numbers from 0 to 4. In Rust, the range syntax0..5also generates values from 0 to 4. Rust’s range syntax is more flexible and can be inclusive (0..=5includes 5). - Iteration over collections: Both languages allow looping over collections, but Rust encourages use of its powerful iterator traits for more control over iteration.
Rust also has a while loop similar to Python’s:
Python:
i = 0
while i < 5:
print(i)
i += 1
Rust:
let mut x = 0;
while x < 5 {
println!("{}", x);
x += 1;
}
Key differences
- Mutability: In Rust, you must declare
ias mutable (mut) if you plan to change its value, while Python doesn’t require such an explicit declaration.
5. Returning Values from if Statements
One unique feature of Rust is that if statements are expressions, meaning they can return values. Python’s if blocks are statements and cannot return values directly without using additional techniques like a ternary operator.
Python:
x = 5
y = 10 if x > 5 else 0
Rust:
let x = 5;
let y = if x > 5 { 10 } else { 0 };
Key Differences:
- Expressions: In Rust, control structures like
ifcan return values directly, making it more expressive in some cases compared to Python. - No ternary operator: Rust doesn’t have a ternary operator because
ifis already an expression.
6. Rust’s main function
In Rust, every standalone program requires a main function, much like a script in Python. However, Python doesn’t require this unless the script needs to be run in a specific context:
Python:
if __name__ == "__main__":
print("Hello, Python!")
Rust:
fn main() {
println!("Hello, Rust!");
}
Key differences
- Entry point: Rust programs must have a
mainfunction as an entry point, whereas Python scripts can be run without one. Theif __name__ == "__main__"guard is a common idiom in Python but not necessary in Rust.
One runnable end-to-end example
// 1. Defining Functions in Rust
fn add(x: i32, y: i32) -> i32 {
x + y
}
fn main() {
// Call the add function
println!("Sum of 2 and 3: {}", add(2, 3));
// 2. Variables and Mutability
let mut x = 10;
x = x + 5;
println!("Updated value of x: {}", x);
// 3. Control Flow: if Statements
if x > 5 {
println!("x is greater than 5");
} else {
println!("x is less than or equal to 5");
}
// 4. Loops in Rust: for Loop
println!("For loop output:");
for i in 0..5 {
println!("{}", i);
}
// 4. Loops in Rust: while Loop
println!("While loop output:");
let mut y = 0;
while y < 5 {
println!("{}", y);
y += 1;
}
// 5. Returning values from if statements
let z = if x > 5 { 10 } else { 0 };
println!("Value of z: {}", z);
// 6. Rust's main function (Already part of the example)
println!("Hello, Rust!");
}
Common mistakes
- Forgetting type annotations in function signatures.
- Forgetting
mutwhen a value must change. - Using semicolons after expressions that should return values.
Quick practice
- Write a function
multiply(x: i32, y: i32) -> i32and call it. - Create a loop that prints numbers
1..=3.
Recap
Rust syntax is familiar in spirit but stricter by design. The big wins are explicitness and compile-time guarantees.
In the next lesson, we’ll cover ownership, borrowing, and lifetimes.
Join the Journey Ahead!
If you're eager to continue this learning journey and stay updated with the latest insights, consider subscribing. By joining our mailing list, you'll receive notifications about new articles, tips, and resources to help you seamlessly pick up Rust by leveraging your Python skills.
Other articles in the series
- 000 - Learning Rust as a Pythonista: A Suggested Path
- 001 - Your First Rust Program
- 003 - Ownership, Borrowing, and Lifetimes
- 004 - Error Handling
- 005 - Structs and Enums
- 006 - Iterators and Closures
- 007 - Traits vs Duck Typing and Protocols
- 008 - Concurrency in Rust for Python Developers
- 009 - Async Concurrency with Tokio
- 010 - Pattern Matching in Rust
- 011 - Macros in Rust