Python Exceptions: Flexible but Dangerous
Python uses exceptions to signal errors. You write your normal logic and catch errors only when needed. This is powerful but can make it easy to forget to handle failures:
Division with Potential Error
def divide(a, b):
return a / b
try:
result = divide(10, 0)
except ZeroDivisionError as e:
print(f"Error: {e}")
fn divide(a: f64, b: f64) -> f64 {
a / b // ⚠️ Will panic at runtime if b == 0
}
// Rust prefers handling errors explicitly
Rust's Result Type: Errors as Values
Rust encourages you to handle errors as part of the type system. Instead of throwing exceptions, functions return a Result
type:
Explicit Error Handling
def safe_divide(a, b):
if b == 0:
return None
return a / b
result = safe_divide(10, 2)
if result is None:
print("Divide by zero!")
else:
print(result)
fn safe_divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err("Divide by zero".to_string())
} else {
Ok(a / b)
}
}
match safe_divide(10.0, 2.0) {
Ok(result) => println!("{}", result),
Err(e) => println!("Error: {}", e),
}
Propagating Errors with ?
In Rust, the ?
operator simplifies error propagation by returning early if an error occurs:
Error Propagation
def read_file(path):
with open(path) as f:
return f.read()
try:
content = read_file("hello.txt")
except IOError as e:
print(f"Failed to read file: {e}")
use std::fs::File;
use std::io::{self, Read};
fn read_file(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
When Rust Panics
Rust does have panics, similar to Python exceptions, but they’re meant for unrecoverable errors. You should reserve panic!
for bugs, not expected runtime errors.
Explicit Panic
raise Exception("This should never happen")
panic!("This should never happen");
Key Takeaways
- Rust's Result type: forces you to handle errors explicitly
- No exceptions: Rust avoids hidden control flow
- ? operator: ergonomically propagates errors
- Panics: should be rare and only used for unrecoverable logic errors
Coming from Python
If you're used to Python's dynamic and flexible error handling, Rust's approach might feel verbose. But in return, you get strong compile-time guarantees and fewer surprises at runtime. With Result
, you always know what might fail — and what you have to do about it.
Pro Tip: Use Result
for anything that can fail, and use ?
to keep your code clean while still being safe.