从Python到Rust - 2
第4章:控制流与函数
4.1 条件语句
if表达式
Rust中的if
是表达式,而不仅仅是语句,这意味着它可以返回值:
// Rust if表达式
fn main() {
let number = 6;
// 基本if语句
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
// if作为表达式
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {}", number);
// 必须返回相同类型
// let number = if condition { 5 } else { "six" }; // 编译错误
}
# Python if语句
def main():
number = 6
# 基本if语句
if number % 4 == 0:
print("number is divisible by 4")
elif number % 3 == 0:
print("number is divisible by 3")
elif number % 2 == 0:
print("number is divisible by 2")
else:
print("number is not divisible by 4, 3, or 2")
# 三元运算符(条件表达式)
condition = True
number = 5 if condition else 6
print(f"The value of number is: {number}")
# Python允许不同类型
number = 5 if condition else "six" # 合法
main()
4.2 循环
loop循环(无限循环)
// Rust无限循环
fn rust_infinite_loop() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // loop可以返回值
}
};
println!("The result is {}", result);
}
// 嵌套循环with标签
fn nested_loops() {
let mut count = 0;
'counting_up: loop {
println!("count = {}", count);
let mut remaining = 10;
loop {
println!("remaining = {}", remaining);
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up; // 跳出外层循环
}
remaining -= 1;
}
count += 1;
}
println!("End count = {}", count);
}
# Python无限循环
def python_infinite_loop():
counter = 0
while True:
counter += 1
if counter == 10:
result = counter * 2
break
print(f"The result is {result}")
# Python没有循环标签,需要使用标志变量
def nested_loops():
count = 0
should_break = False
while not should_break:
print(f"count = {count}")
remaining = 10
while remaining > 0:
print(f"remaining = {remaining}")
if remaining == 9:
break
if count == 2:
should_break = True
break
remaining -= 1
if not should_break:
count += 1
print(f"End count = {count}")
while循环
// Rust while循环
fn rust_while_loop() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
}
# Python while循环
def python_while_loop():
number = 3
while number != 0:
print(f"{number}!")
number -= 1
print("LIFTOFF!!!")
for循环
// Rust for循环
fn rust_for_loops() {
// 遍历数组
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {}", element);
}
// 使用范围
for number in (1..4).rev() { // rev()反转
println!("{}!", number);
}
println!("LIFTOFF!!!");
// 带索引的遍历
for (index, value) in a.iter().enumerate() {
println!("Index: {}, Value: {}", index, value);
}
// 遍历引用避免所有权转移
let vec = vec![1, 2, 3, 4, 5];
for item in &vec {
println!("item: {}", item);
}
println!("vec is still usable: {:?}", vec);
}
# Python for循环
def python_for_loops():
# 遍历列表
a = [10, 20, 30, 40, 50]
for element in a:
print(f"the value is: {element}")
# 使用range
for number in reversed(range(1, 4)):
print(f"{number}!")
print("LIFTOFF!!!")
# 带索引的遍历
for index, value in enumerate(a):
print(f"Index: {index}, Value: {value}")
# Python中不需要考虑所有权
vec = [1, 2, 3, 4, 5]
for item in vec:
print(f"item: {item}")
print(f"vec is still usable: {vec}")
4.3 模式匹配 - match表达式
这是Rust最强大的特性之一,类似Python 3.10+的match语句,但更强大:
基本match用法
// Rust match表达式
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn main() {
let coin = Coin::Penny;
println!("Value: {} cents", value_in_cents(coin));
// match必须穷尽所有可能
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
other => move_player(other), // 捕获其他值
// _ => (), // 或者使用_忽略其他值
}
}
fn add_fancy_hat() {}
fn remove_fancy_hat() {}
fn move_player(num_spaces: u8) {}
# Python match语句(3.10+)
from enum import Enum
class Coin(Enum):
PENNY = "penny"
NICKEL = "nickel"
DIME = "dime"
QUARTER = "quarter"
def value_in_cents(coin):
match coin:
case Coin.PENNY:
return 1
case Coin.NICKEL:
return 5
case Coin.DIME:
return 10
case Coin.QUARTER:
return 25
def main():
coin = Coin.PENNY
print(f"Value: {value_in_cents(coin)} cents")
# Python match不要求穷尽,但建议使用_
dice_roll = 9
match dice_roll:
case 3:
add_fancy_hat()
case 7:
remove_fancy_hat()
case other:
move_player(other)
def add_fancy_hat():
pass
def remove_fancy_hat():
pass
def move_player(num_spaces):
pass
main()
匹配Option和Result
// Rust中匹配Option
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
println!("six: {:?}", six);
println!("none: {:?}", none);
// if let语法糖
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
// while let循环
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() {
println!("{}", top);
}
}
# Python中处理Optional值
from typing import Optional
def plus_one(x: Optional[int]) -> Optional[int]:
if x is None:
return None
else:
return x + 1
def main():
five = 5 # Python没有Option类型
six = plus_one(five)
none = plus_one(None)
print(f"six: {six}")
print(f"none: {none}")
# Python中的条件检查
some_value = 0
if some_value == 3:
print("three")
# Python中的while循环
stack = [1, 2, 3]
while stack:
top = stack.pop()
print(top)
main()
4.4 函数定义与参数
基本函数语法
// Rust函数
fn main() {
println!("Hello, world!");
another_function(5);
print_labeled_measurement(5, 'h');
let x = five();
println!("The value of x is: {}", x);
let x = plus_one(5);
println!("The value of x is: {}", x);
}
fn another_function(x: i32) {
println!("The value of x is: {}", x);
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("The measurement is: {}{}", value, unit_label);
}
// 返回值
fn five() -> i32 {
5 // 表达式,没有分号
}
fn plus_one(x: i32) -> i32 {
x + 1 // 表达式返回值
}
# Python函数
def main():
print("Hello, world!")
another_function(5)
print_labeled_measurement(5, 'h')
x = five()
print(f"The value of x is: {x}")
x = plus_one(5)
print(f"The value of x is: {x}")
def another_function(x):
print(f"The value of x is: {x}")
def print_labeled_measurement(value, unit_label):
print(f"The measurement is: {value}{unit_label}")
# 返回值
def five():
return 5
def plus_one(x):
return x + 1
if __name__ == "__main__":
main()
高级函数特性
// Rust高级函数特性
fn main() {
// 函数指针
let f: fn(i32) -> i32 = add_one;
println!("Result: {}", f(5));
// 闭包
let add_two = |x| x + 2;
println!("Result: {}", add_two(5));
// 高阶函数
let numbers = vec![1, 2, 3, 4, 5];
let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
println!("Doubled: {:?}", doubled);
// 函数作为参数
let result = apply_operation(5, 3, add);
println!("5 + 3 = {}", result);
let result = apply_operation(5, 3, multiply);
println!("5 * 3 = {}", result);
}
fn add_one(x: i32) -> i32 {
x + 1
}
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn multiply(a: i32, b: i32) -> i32 {
a * b
}
fn apply_operation<F>(a: i32, b: i32, op: F) -> i32
where
F: Fn(i32, i32) -> i32,
{
op(a, b)
}
# Python高级函数特性
def main():
# 函数是第一类对象
f = add_one
print(f"Result: {f(5)}")
# Lambda函数
add_two = lambda x: x + 2
print(f"Result: {add_two(5)}")
# 高阶函数
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
print(f"Doubled: {doubled}")
# 函数作为参数
result = apply_operation(5, 3, add)
print(f"5 + 3 = {result}")
result = apply_operation(5, 3, multiply)
print(f"5 * 3 = {result}")
def add_one(x):
return x + 1
def add(a, b):
return a + b
def multiply(a, b):
return a * b
def apply_operation(a, b, op):
return op(a, b)
if __name__ == "__main__":
main()
4.5 闭包 (Closures)
闭包基础
// Rust闭包
fn main() {
let expensive_closure = |num: u32| -> u32 {
println!("calculating slowly...");
std::thread::sleep(std::time::Duration::from_secs(2));
num
};
// 类型推断
let add_one = |x| x + 1;
println!("Result: {}", add_one(5));
// 捕获环境
let x = 4;
let equal_to_x = |z| z == x; // 捕获x
let y = 4;
assert!(equal_to_x(y));
// 移动闭包
let x = vec![1, 2, 3];
let equal_to_x = move |z| z == x; // 移动x的所有权
// println!("can't use x here: {:?}", x); // 编译错误
let y = vec![1, 2, 3];
assert!(equal_to_x(y));
}
// 存储闭包的结构体
struct Cacher<T>
where
T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}
impl<T> Cacher<T>
where
T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
}
}
}
}
# Python闭包
import time
from typing import Callable, Optional
def main():
def expensive_closure(num: int) -> int:
print("calculating slowly...")
time.sleep(2)
return num
# 简单闭包
add_one = lambda x: x + 1
print(f"Result: {add_one(5)}")
# 捕获环境
x = 4
def equal_to_x(z):
return z == x # 自动捕获x
y = 4
assert equal_to_x(y)
# Python闭包自动捕获,无需特殊语法
x = [1, 2, 3]
def equal_to_x(z):
return z == x
print(f"can still use x here: {x}") # Python中x仍然可用
y = [1, 2, 3]
assert equal_to_x(y)
# 缓存闭包的类
class Cacher:
def __init__(self, calculation: Callable[[int], int]):
self.calculation = calculation
self.value: Optional[int] = None
def get_value(self, arg: int) -> int:
if self.value is None:
self.value = self.calculation(arg)
return self.value
if __name__ == "__main__":
main()
4.6 迭代器
迭代器基础
// Rust迭代器
fn main() {
let v1 = vec![1, 2, 3];
// 创建迭代器
let v1_iter = v1.iter();
// for循环消费迭代器
for val in v1_iter {
println!("Got: {}", val);
}
// 迭代器适配器
let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
println!("v2: {:?}", v2);
// 使用闭包的迭代器
let shoes = vec![
Shoe { size: 10, style: String::from("sneaker") },
Shoe { size: 13, style: String::from("sandal") },
Shoe { size: 10, style: String::from("boot") },
];
let in_my_size = shoes_in_my_size(shoes, 10);
println!("Shoes in my size: {:?}", in_my_size);
}
#[derive(PartialEq, Debug)]
struct Shoe {
size: u32,
style: String,
}
fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
shoes.into_iter().filter(|s| s.size == shoe_size).collect()
}
// 自定义迭代器
struct Counter {
current: usize,
max: usize,
}
impl Counter {
fn new(max: usize) -> Counter {
Counter { current: 0, max }
}
}
impl Iterator for Counter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.max {
let current = self.current;
self.current += 1;
Some(current)
} else {
None
}
}
}
# Python迭代器
def main():
v1 = [1, 2, 3]
# 创建迭代器
v1_iter = iter(v1)
# for循环消费迭代器
for val in v1_iter:
print(f"Got: {val}")
# 使用map和列表推导
v1 = [1, 2, 3]
v2 = list(map(lambda x: x + 1, v1))
# 或者使用列表推导
v2 = [x + 1 for x in v1]
print(f"v2: {v2}")
# 使用filter
shoes = [
{"size": 10, "style": "sneaker"},
{"size": 13, "style": "sandal"},
{"size": 10, "style": "boot"},
]
in_my_size = shoes_in_my_size(shoes, 10)
print(f"Shoes in my size: {in_my_size}")
def shoes_in_my_size(shoes, shoe_size):
return list(filter(lambda s: s["size"] == shoe_size, shoes))
# 自定义迭代器
class Counter:
def __init__(self, max_val):
self.current = 0
self.max = max_val
def __iter__(self):
return self
def __next__(self):
if self.current < self.max:
current = self.current
self.current += 1
return current
else:
raise StopIteration
# 使用生成器(更简单的方式)
def counter_generator(max_val):
current = 0
while current < max_val:
yield current
current += 1
if __name__ == "__main__":
main()
4.7 实践练习
练习1:斐波那契数列生成器
// Rust版本:斐波那契数列
struct Fibonacci {
current: u64,
next: u64,
}
impl Fibonacci {
fn new() -> Self {
Fibonacci { current: 0, next: 1 }
}
}
impl Iterator for Fibonacci {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
let current = self.current;
self.current = self.next;
self.next = current + self.next;
Some(current)
}
}
fn fibonacci_recursive(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2),
}
}
fn main() {
// 使用迭代器
let fib_seq: Vec<u64> = Fibonacci::new().take(10).collect();
println!("Fibonacci sequence: {:?}", fib_seq);
// 使用递归
for i in 0..10 {
println!("fib({}) = {}", i, fibonacci_recursive(i));
}
// 使用循环(更高效)
fn fibonacci_iterative(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => {
let (mut prev, mut current) = (0, 1);
for _ in 2..=n {
let next = prev + current;
prev = current;
current = next;
}
current
}
}
}
for i in 0..10 {
println!("fib_iter({}) = {}", i, fibonacci_iterative(i));
}
}
# Python版本:斐波那契数列
class Fibonacci:
def __init__(self):
self.current = 0
self.next = 1
def __iter__(self):
return self
def __next__(self):
current = self.current
self.current = self.next
self.next = current + self.next
return current
def fibonacci_recursive(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
def fibonacci_generator():
"""使用生成器的更简洁版本"""
a, b = 0, 1
while True:
yield a
a, b = b, a + b
def main():
# 使用迭代器
fib = Fibonacci()
fib_seq = [next(fib) for _ in range(10)]
print(f"Fibonacci sequence: {fib_seq}")
# 使用递归
for i in range(10):
print(f"fib({i}) = {fibonacci_recursive(i)}")
# 使用迭代(更高效)
def fibonacci_iterative(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
prev, current = 0, 1
for _ in range(2, n + 1):
prev, current = current, prev + current
return current
for i in range(10):
print(f"fib_iter({i}) = {fibonacci_iterative(i)}")
# 使用生成器
fib_gen = fibonacci_generator()
fib_seq_gen = [next(fib_gen) for _ in range(10)]
print(f"Fibonacci from generator: {fib_seq_gen}")
if __name__ == "__main__":
main()
练习2:数据处理管道
// Rust数据处理管道
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 函数式处理管道
let result: Vec<i32> = numbers
.iter()
.filter(|&&x| x % 2 == 0) // 过滤偶数
.map(|&x| x * x) // 平方
.filter(|&&x| x > 10) // 过滤大于10的
.collect();
println!("Processed numbers: {:?}", result);
// 使用自定义函数
let result2: Vec<i32> = numbers
.iter()
.copied()
.filter(is_even)
.map(square)
.filter(|&x| x > 10)
.collect();
println!("Processed with functions: {:?}", result2);
// 复杂数据处理
let words = vec!["rust", "python", "javascript", "go", "c++"];
let long_words: Vec<String> = words
.iter()
.filter(|word| word.len() > 4)
.map(|word| word.to_uppercase())
.collect();
println!("Long words: {:?}", long_words);
}
fn is_even(x: i32) -> bool {
x % 2 == 0
}
fn square(x: i32) -> i32 {
x * x
}
# Python数据处理管道
def main():
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 函数式处理管道
result = list(
filter(lambda x: x > 10,
map(lambda x: x * x,
filter(lambda x: x % 2 == 0, numbers)
)
)
)
# 更Pythonic的方式:列表推导
result = [x * x for x in numbers if x % 2 == 0 and x * x > 10]
print(f"Processed numbers: {result}")
# 使用自定义函数
def is_even(x):
return x % 2 == 0
def square(x):
return x * x
result2 = [square(x) for x in numbers if is_even(x) and square(x) > 10]
print(f"Processed with functions: {result2}")
# 复杂数据处理
words = ["rust", "python", "javascript", "go", "c++"]
long_words = [word.upper() for word in words if len(word) > 4]
print(f"Long words: {long_words}")
if __name__ == "__main__":
main()
4.8 本章小结
通过本章学习,你应该掌握:
- 控制流:if表达式、循环(loop、while、for)
- 模式匹配:match表达式的强大功能
- 函数:函数定义、参数传递、返回值
- 闭包:捕获环境变量的匿名函数
- 迭代器:函数式编程的核心概念
与Python的关键差异:
特性 | Rust | Python |
---|---|---|
if语句 | 表达式,可返回值 | 语句,不返回值 |
模式匹配 | 必须穷尽,编译时检查 | 可选穷尽,运行时执行 |
循环标签 | 支持break到外层循环 | 不支持,需要标志变量 |
闭包 | 需要显式捕获(move) | 自动捕获 |
迭代器 | 惰性求值,零成本抽象 | 惰性求值,有运行时开销 |
下一章预告: 我们将学习Rust的复合数据类型,包括结构体、枚举等。
第5章:复合数据类型
5.1 结构体 (Structs)
结构体让你可以创建比元组更有意义的复合类型:
定义和实例化结构体
// Rust结构体
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
// 创建实例
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
// 访问字段
println!("User email: {}", user1.email);
// 可变实例
let mut user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: true,
sign_in_count: 1,
};
user2.email = String::from("anotheremail@example.com");
// 结构体更新语法
let user3 = User {
email: String::from("another@example.com"),
..user1 // 使用user1的其他字段
};
// 注意:user1的String字段被移动了,不能再使用
// println!("{}", user1.username); // 编译错误
println!("User3 username: {}", user3.username);
}
// 构造函数
fn build_user(email: String, username: String) -> User {
User {
email, // 字段初始化简写
username, // 当参数名与字段名相同时
active: true,
sign_in_count: 1,
}
}
# Python类(最接近Rust结构体的概念)
from dataclasses import dataclass
from typing import Optional
@dataclass
class User:
email: str
username: str
active: bool = True
sign_in_count: int = 1
def main():
# 创建实例
user1 = User(
email="someone@example.com",
username="someusername123",
active=True,
sign_in_count=1
)
# 访问字段
print(f"User email: {user1.email}")
# Python对象默认可变
user2 = User(
email="another@example.com",
username="anotherusername567"
)
user2.email = "anotheremail@example.com"
# Python中的"更新"需要手动处理
import copy
user3 = copy.copy(user1)
user3.email = "another@example.com"
# Python中user1仍然可用
print(f"User1 still accessible: {user1.username}")
print(f"User3 username: {user3.username}")
# 构造函数
def build_user(email: str, username: str) -> User:
return User(
email=email,
username=username,
active=True,
sign_in_count=1
)
if __name__ == "__main__":
main()
元组结构体和单元结构体
// Rust特殊结构体类型
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
// 单元结构体(类似于空元组)
struct AlwaysEqual;
fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
// 虽然Color和Point有相同的字段,但它们是不同的类型
// let color: Color = origin; // 编译错误
// 访问元组结构体字段
println!("Black: ({}, {}, {})", black.0, black.1, black.2);
let subject = AlwaysEqual;
}
# Python中的类似概念
from typing import NamedTuple
class Color(NamedTuple):
red: int
green: int
blue: int
class Point(NamedTuple):
x: int
y: int
z: int
class AlwaysEqual:
"""空类,类似单元结构体"""
pass
def main():
black = Color(0, 0, 0)
origin = Point(0, 0, 0)
# Python中可以直接赋值(类型检查器会警告)
# color = origin # 类型不匹配,但运行时不报错
# 访问字段
print(f"Black: ({black.red}, {black.green}, {black.blue})")
# 或者使用索引(对于NamedTuple)
print(f"Black: ({black[0]}, {black[1]}, {black[2]})")
subject = AlwaysEqual()
if __name__ == "__main__":
main()
5.2 方法语法
定义方法
// Rust方法定义
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 方法(需要self参数)
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
// 关联函数(不需要self参数,类似静态方法)
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
// 可变引用方法
fn double_size(&mut self) {
self.width *= 2;
self.height *= 2;
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
let rect2 = Rectangle {
width: 10,
height: 40,
};
let rect3 = Rectangle {
width: 60,
height: 45,
};
println!("Area of rect1: {}", rect1.area());
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
// 关联函数调用
let square = Rectangle::square(20);
println!("Square: {:?}", square);
// 可变方法
let mut rect4 = Rectangle {
width: 10,
height: 10,
};
println!("Before: {:?}", rect4);
rect4.double_size();
println!("After: {:?}", rect4);
}
# Python类方法
class Rectangle:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
def __repr__(self):
return f"Rectangle(width={self.width}, height={self.height})"
# 实例方法
def area(self) -> int:
return self.width * self.height
def can_hold(self, other: 'Rectangle') -> bool:
return self.width > other.width and self.height > other.height
# 类方法(类似关联函数)
@classmethod
def square(cls, size: int) -> 'Rectangle':
return cls(size, size)
# Python中所有方法都可以修改对象
def double_size(self):
self.width *= 2
self.height *= 2
def main():
rect1 = Rectangle(30, 50)
rect2 = Rectangle(10, 40)
rect3 = Rectangle(60, 45)
print(f"Area of rect1: {rect1.area()}")
print(f"Can rect1 hold rect2? {rect1.can_hold(rect2)}")
print(f"Can rect1 hold rect3? {rect1.can_hold(rect3)}")
# 类方法调用
square = Rectangle.square(20)
print(f"Square: {square}")
# 修改方法
rect4 = Rectangle(10, 10)
print(f"Before: {rect4}")
rect4.double_size()
print(f"After: {rect4}")
if __name__ == "__main__":
main()
5.3 枚举 (Enums)
枚举让你可以列举一个类型的所有可能值:
基本枚举
// Rust枚举
enum IpAddrKind {
V4,
V6,
}
// 带数据的枚举
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
// 复杂枚举
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
match self {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Write: {}", text),
Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b),
}
}
}
fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
route(four);
route(six);
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
let m = Message::Write(String::from("hello"));
m.call();
let m2 = Message::Move { x: 10, y: 20 };
m2.call();
}
fn route(ip_kind: IpAddrKind) {
match ip_kind {
IpAddrKind::V4 => println!("IPv4"),
IpAddrKind::V6 => println!("IPv6"),
}
}
# Python枚举
from enum import Enum, auto
from typing import Union, Tuple
from dataclasses import dataclass
class IpAddrKind(Enum):
V4 = auto()
V6 = auto()
# Python需要使用Union类型或继承来模拟带数据的枚举
@dataclass
class IPv4:
octets: Tuple[int, int, int, int]
@dataclass
class IPv6:
address: str
IpAddr = Union[IPv4, IPv6]
# 复杂枚举需要使用类继承
class Message:
def call(self):
if isinstance(self, Quit):
print("Quit")
elif isinstance(self, Move):
print(f"Move to ({self.x}, {self.y})")
elif isinstance(self, Write):
print(f"Write: {self.text}")
elif isinstance(self, ChangeColor):
print(f"Change color to ({self.r}, {self.g}, {self.b})")
class Quit(Message):
pass
@dataclass
class Move(Message):
x: int
y: int
@dataclass
class Write(Message):
text: str
@dataclass
class ChangeColor(Message):
r: int
g: int
b: int
def main():
four = IpAddrKind.V4
six = IpAddrKind.V6
route(four)
route(six)
home = IPv4((127, 0, 0, 1))
loopback = IPv6("::1")
m = Write("hello")
m.call()
m2 = Move(10, 20)
m2.call()
def route(ip_kind: IpAddrKind):
if ip_kind == IpAddrKind.V4:
print("IPv4")
elif ip_kind == IpAddrKind.V6:
print("IPv6")
if __name__ == "__main__":
main()
5.4 Option枚举
Option是Rust标准库中最重要的枚举之一:
// Rust Option枚举
fn main() {
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
// 使用match处理Option
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = match y {
Some(value) => x + value,
None => x,
};
println!("Sum: {}", sum);
// 使用if let简化
if let Some(value) = y {
println!("y has value: {}", value);
}
// Option的常用方法
let number = Some(42);
// unwrap: 如果是Some则返回值,如果是None则panic
println!("Number: {}", number.unwrap());
// unwrap_or: 如果是None则返回默认值
let none_number: Option<i32> = None;
println!("Number or default: {}", none_number.unwrap_or(0));
// map: 对Some中的值进行变换
let doubled = number.map(|x| x * 2);
println!("Doubled: {:?}", doubled);
// and_then: 链式操作
let result = number
.map(|x| x * 2)
.and_then(|x| if x > 50 { Some(x) } else { None });
println!("Chained result: {:?}", result);
}
# Python Optional类型
from typing import Optional
def main():
# Python使用None表示缺失值
some_number: Optional[int] = 5
some_string: Optional[str] = "a string"
absent_number: Optional[int] = None
# Python中需要显式检查None
x = 5
y: Optional[int] = 5
if y is not None:
sum_val = x + y
else:
sum_val = x
print(f"Sum: {sum_val}")
# 使用海象操作符(Python 3.8+)
if (value := y) is not None:
print(f"y has value: {value}")
# Python没有unwrap,但可以直接访问(可能出错)
number: Optional[int] = 42
if number is not None:
print(f"Number: {number}")
# 使用or提供默认值
none_number: Optional[int] = None
print(f"Number or default: {none_number or 0}")
# 使用map需要自定义函数
def optional_map(opt_val, func):
return func(opt_val) if opt_val is not None else None
doubled = optional_map(number, lambda x: x * 2)
print(f"Doubled: {doubled}")
# 链式操作需要手动处理
result = number
if result is not None:
result = result * 2
if result <= 50:
result = None
print(f"Chained result: {result}")
if __name__ == "__main__":
main()
5.5 实践练习
练习1:构建一个简单的形状计算器
// Rust形状计算器
#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
Triangle { base: f64, height: f64 },
}
impl Shape {
fn area(&self) -> f64 {
match self {
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
Shape::Rectangle { width, height } => width * height,
Shape::Triangle { base, height } => 0.5 * base * height,
}
}
fn perimeter(&self) -> f64 {
match self {
Shape::Circle { radius } => 2.0 * std::f64::consts::PI * radius,
Shape::Rectangle { width, height } => 2.0 * (width + height),
Shape::Triangle { base, height } => {
// 假设是等腰三角形
let side = (height * height + (base / 2.0) * (base / 2.0)).sqrt();
base + 2.0 * side
}
}
}
}
fn main() {
let shapes = vec![
Shape::Circle { radius: 5.0 },
Shape::Rectangle { width: 10.0, height: 20.0 },
Shape::Triangle { base: 8.0, height: 6.0 },
];
for shape in &shapes {
println!("{:?}", shape);
println!("Area: {:.2}", shape.area());
println!("Perimeter: {:.2}", shape.perimeter());
println!("---");
}
// 计算总面积
let total_area: f64 = shapes.iter().map(|shape| shape.area()).sum();
println!("Total area: {:.2}", total_area);
}
# Python形状计算器
import math
from abc import ABC, abstractmethod
from typing import List
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
@abstractmethod
def perimeter(self) -> float:
pass
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return math.pi * self.radius ** 2
def perimeter(self) -> float:
return 2 * math.pi * self.radius
def __repr__(self):
return f"Circle(radius={self.radius})"
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
def perimeter(self) -> float:
return 2 * (self.width + self.height)
def __repr__(self):
return f"Rectangle(width={self.width}, height={self.height})"
class Triangle(Shape):
def __init__(self, base: float, height: float):
self.base = base
self.height = height
def area(self) -> float:
return 0.5 * self.base * self.height
def perimeter(self) -> float:
# 假设是等腰三角形
side = math.sqrt(self.height ** 2 + (self.base / 2) ** 2)
return self.base + 2 * side
def __repr__(self):
return f"Triangle(base={self.base}, height={self.height})"
def main():
shapes: List[Shape] = [
Circle(5.0),
Rectangle(10.0, 20.0),
Triangle(8.0, 6.0),
]
for shape in shapes:
print(shape)
print(f"Area: {shape.area():.2f}")
print(f"Perimeter: {shape.perimeter():.2f}")
print("---")
# 计算总面积
total_area = sum(shape.area() for shape in shapes)
print(f"Total area: {total_area:.2f}")
if __name__ == "__main__":
main()
练习2:构建一个简单的库存管理系统
// Rust库存管理系统
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct Product {
id: u32,
name: String,
price: f64,
quantity: u32,
}
impl Product {
fn new(id: u32, name: String, price: f64, quantity: u32) -> Self {
Product { id, name, price, quantity }
}
fn total_value(&self) -> f64 {
self.price * self.quantity as f64
}
fn is_low_stock(&self, threshold: u32) -> bool {
self.quantity < threshold
}
}
struct Inventory {
products: HashMap<u32, Product>,
}
impl Inventory {
fn new() -> Self {
Inventory {
products: HashMap::new(),
}
}
fn add_product(&mut self, product: Product) {
self.products.insert(product.id, product);
}
fn update_quantity(&mut self, id: u32, new_quantity: u32) -> Option<&Product> {
if let Some(product) = self.products.get_mut(&id) {
product.quantity = new_quantity;
Some(product)
} else {
None
}
}
fn get_product(&self, id: u32) -> Option<&Product> {
self.products.get(&id)
}
fn total_inventory_value(&self) -> f64 {
self.products.values().map(|p| p.total_value()).sum()
}
fn low_stock_products(&self, threshold: u32) -> Vec<&Product> {
self.products
.values()
.filter(|p| p.is_low_stock(threshold))
.collect()
}
}
fn main() {
let mut inventory = Inventory::new();
// 添加产品
inventory.add_product(Product::new(1, "Laptop".to_string(), 999.99, 10));
inventory.add_product(Product::new(2, "Mouse".to_string(), 29.99, 5));
inventory.add_product(Product::new(3, "Keyboard".to_string(), 79.99, 2));
// 查看产品
if let Some(laptop) = inventory.get_product(1) {
println!("Found laptop: {:?}", laptop);
println!("Total value: ${:.2}", laptop.total_value());
}
// 更新数量
inventory.update_quantity(2, 50);
// 计算总库存价值
println!("Total inventory value: ${:.2}", inventory.total_inventory_value());
// 查找低库存产品
let low_stock = inventory.low_stock_products(10);
println!("Low stock products:");
for product in low_stock {
println!(" {:?}", product);
}
}
# Python库存管理系统
from typing import Dict, List, Optional
class Product:
def __init__(self, id: int, name: str, price: float, quantity: int):
self.id = id
self.name = name
self.price = price
self.quantity = quantity
def total_value(self) -> float:
return self.price * self.quantity
def is_low_stock(self, threshold: int) -> bool:
return self.quantity < threshold
def __repr__(self):
return f"Product(id={self.id}, name='{self.name}', price={self.price}, quantity={self.quantity})"
class Inventory:
def __init__(self):
self.products: Dict[int, Product] = {}
def add_product(self, product: Product):
self.products[product.id] = product
def update_quantity(self, id: int, new_quantity: int) -> Optional[Product]:
if id in self.products:
self.products[id].quantity = new_quantity
return self.products[id]
return None
def get_product(self, id: int) -> Optional[Product]:
return self.products.get(id)
def total_inventory_value(self) -> float:
return sum(product.total_value() for product in self.products.values())
def low_stock_products(self, threshold: int) -> List[Product]:
return [product for product in self.products.values()
if product.is_low_stock(threshold)]
def main():
inventory = Inventory()
# 添加产品
inventory.add_product(Product(1, "Laptop", 999.99, 10))
inventory.add_product(Product(2, "Mouse", 29.99, 5))
inventory.add_product(Product(3, "Keyboard", 79.99, 2))
# 查看产品
laptop = inventory.get_product(1)
if laptop:
print(f"Found laptop: {laptop}")
print(f"Total value: ${laptop.total_value():.2f}")
# 更新数量
inventory.update_quantity(2, 50)
# 计算总库存价值
print(f"Total inventory value: ${inventory.total_inventory_value():.2f}")
# 查找低库存产品
low_stock = inventory.low_stock_products(10)
print("Low stock products:")
for product in low_stock:
print(f" {product}")
if __name__ == "__main__":
main()
5.6 本章小结
通过本章学习,你应该掌握:
- 结构体:定义自定义数据类型,组织相关数据
- 方法:为结构体添加行为,关联函数
- 枚举:定义可能值的有限集合,强大的模式匹配
- Option类型:安全地处理可能不存在的值
与Python的关键差异:
特性 | Rust | Python |
---|---|---|
结构体 | 编译时类型检查,所有权语义 | 运行时类型,引用语义 |
方法 | 需要显式self参数类型 | 默认可变self |
枚举 | 可携带数据,强制匹配 | 简单值,可选匹配 |
空值处理 | Option类型,编译时安全 | None值,运行时检查 |
下一章预告: 我们将学习Rust的错误处理机制,包括Result类型和错误传播。
第6章:错误处理
6.1 Rust的错误处理哲学
Rust将错误分为两大类:可恢复错误和不可恢复错误。这与Python的异常机制有根本不同:
- 可恢复错误:如文件未找到,用
Result<T, E>
处理 - 不可恢复错误:如数组越界,用
panic!
处理
Python vs Rust错误处理对比
# Python使用异常处理所有错误
def read_file(filename):
try:
with open(filename, 'r') as f:
return f.read()
except FileNotFoundError:
print(f"File {filename} not found")
return None
except IOError as e:
print(f"Error reading file: {e}")
return None
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
print("Cannot divide by zero")
return None
// Rust使用Result处理可恢复错误
use std::fs;
use std::io;
fn read_file(filename: &str) -> Result<String, io::Error> {
fs::read_to_string(filename)
}
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err("Cannot divide by zero".to_string())
} else {
Ok(a / b)
}
}
fn main() {
// 处理文件读取错误
match read_file("hello.txt") {
Ok(contents) => println!("File contents: {}", contents),
Err(error) => println!("Error reading file: {}", error),
}
// 处理除法错误
match divide(10.0, 0.0) {
Ok(result) => println!("Result: {}", result),
Err(error) => println!("Error: {}", error),
}
}
6.2 panic! - 不可恢复错误
panic!基础
// Rust panic!示例
fn main() {
// 显式panic
// panic!("crash and burn");
// 数组越界会导致panic
let v = vec![1, 2, 3];
// v[99]; // 这会panic
// 安全的数组访问
match v.get(99) {
Some(value) => println!("Value: {}", value),
None => println!("Index out of bounds"),
}
// 设置panic时的行为
// 在Cargo.toml中设置:
// [profile.release]
// panic = 'abort' // 直接终止而不是展开栈
}
fn might_panic(should_panic: bool) {
if should_panic {
panic!("This function panicked!");
}
println!("No panic occurred");
}
# Python异常机制
def main():
# Python中的异常
try:
# raise Exception("crash and burn")
pass
except Exception as e:
print(f"Caught exception: {e}")
# 列表越界抛出异常
v = [1, 2, 3]
try:
print(v[99]) # 抛出IndexError
except IndexError:
print("Index out of bounds")
# 安全的访问方式
if 99 < len(v):
print(f"Value: {v[99]}")
else:
print("Index out of bounds")
def might_raise(should_raise):
if should_raise:
raise Exception("This function raised an exception!")
print("No exception occurred")
if __name__ == "__main__":
main()
6.3 Result<T, E> - 可恢复错误
Result基础
// Rust Result类型
use std::fs::File;
use std::io::ErrorKind;
fn main() {
// 基本Result处理
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => panic!("Problem creating the file: {:?}", e),
},
other_error => {
panic!("Problem opening the file: {:?}", other_error);
}
},
};
// 使用unwrap_or_else简化
let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
if error.kind() == ErrorKind::NotFound {
File::create("hello.txt").unwrap_or_else(|error| {
panic!("Problem creating the file: {:?}", error);
})
} else {
panic!("Problem opening the file: {:?}", error);
}
});
}
// 自定义Result类型
#[derive(Debug)]
enum MathError {
DivisionByZero,
NegativeSquareRoot,
}
fn safe_divide(a: f64, b: f64) -> Result<f64, MathError> {
if b == 0.0 {
Err(MathError::DivisionByZero)
} else {
Ok(a / b)
}
}
fn safe_sqrt(x: f64) -> Result<f64, MathError> {
if x < 0.0 {
Err(MathError::NegativeSquareRoot)
} else {
Ok(x.sqrt())
}
}
# Python自定义异常
class MathError(Exception):
pass
class DivisionByZeroError(MathError):
pass
class NegativeSquareRootError(MathError):
pass
def safe_divide(a, b):
if b == 0:
raise DivisionByZeroError("Cannot divide by zero")
return a / b
def safe_sqrt(x):
if x < 0:
raise NegativeSquareRootError("Cannot take square root of negative number")
return x ** 0.5
def main():
# 文件操作
try:
with open("hello.txt", 'r') as f:
content = f.read()
except FileNotFoundError:
try:
with open("hello.txt", 'w') as f:
f.write("")
print("Created new file")
except IOError as e:
print(f"Problem creating file: {e}")
except IOError as e:
print(f"Problem opening file: {e}")
# 数学操作
try:
result = safe_divide(10, 0)
print(f"Division result: {result}")
except DivisionByZeroError as e:
print(f"Math error: {e}")
try:
result = safe_sqrt(-1)
print(f"Square root result: {result}")
except NegativeSquareRootError as e:
print(f"Math error: {e}")
if __name__ == "__main__":
main()
6.4 unwrap和expect
错误处理的快捷方式
// Rust unwrap和expect
use std::fs::File;
fn main() {
// unwrap: 如果是Ok则返回值,如果是Err则panic
let greeting_file = File::open("hello.txt").unwrap();
// expect: 类似unwrap,但可以自定义panic消息
let greeting_file = File::open("hello.txt")
.expect("hello.txt should be included in this project");
// 更安全的方式:使用if let
if let Ok(file) = File::open("hello.txt") {
println!("File opened successfully");
} else {
println!("Failed to open file");
}
// 或者使用match
match File::open("hello.txt") {
Ok(file) => println!("File opened: {:?}", file),
Err(error) => println!("Failed to open file: {}", error),
}
// Result的其他有用方法
let result: Result<i32, &str> = Ok(42);
// is_ok和is_err
if result.is_ok() {
println!("Result is ok");
}
// unwrap_or: 提供默认值
let value = result.unwrap_or(0);
println!("Value: {}", value);
// map: 变换Ok值
let doubled = result.map(|x| x * 2);
println!("Doubled: {:?}", doubled);
// map_err: 变换Err值
let result_with_mapped_error = result.map_err(|e| format!("Error: {}", e));
println!("Mapped error: {:?}", result_with_mapped_error);
}
# Python没有直接等价物,但可以创建类似功能
def unwrap(result, default_exception=None):
"""模拟Rust的unwrap"""
if isinstance(result, Exception):
if default_exception:
raise default_exception
else:
raise result
return result
def expect(result, message):
"""模拟Rust的expect"""
if isinstance(result, Exception):
raise Exception(message)
return result
def main():
# Python中通常直接处理异常
try:
with open("hello.txt", 'r') as f:
content = f.read()
print("File opened successfully")
except FileNotFoundError:
print("Failed to open file")
# 模拟Result行为
def safe_operation():
try:
with open("hello.txt", 'r') as f:
return f.read()
except FileNotFoundError as e:
return e
result = safe_operation()
# 检查是否为异常
if isinstance(result, Exception):
print("Operation failed")
else:
print(f"Operation succeeded: {result}")
# 使用默认值
def get_value_or_default(operation, default):
try:
return operation()
except:
return default
value = get_value_or_default(lambda: int("not_a_number"), 0)
print(f"Value: {value}")
if __name__ == "__main__":
main()
6.5 错误传播 - ? 操作符
? 操作符简化错误传播
// Rust错误传播
use std::fs::File;
use std::io::{self, Read};
// 传统的错误传播方式
fn read_username_from_file_verbose() -> Result<String, io::Error> {
let username_file_result = File::open("hello.txt");
let mut username_file = match username_file_result {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut username = String::new();
match username_file.read_to_string(&mut username) {
Ok(_) => Ok(username),
Err(e) => Err(e),
}
}
// 使用?操作符简化
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("hello.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}
// 进一步简化
fn read_username_from_file_short() -> Result<String, io::Error> {
let mut username = String::new();
File::open("hello.txt")?.read_to_string(&mut username)?;
Ok(username)
}
// 最简化(使用标准库函数)
fn read_username_from_file_shortest() -> Result<String, io::Error> {
std::fs::read_to_string("hello.txt")
}
// ?操作符也可以用于Option
fn last_char_of_first_line(text: &str) -> Option<char> {
text.lines().next()?.chars().last()
}
fn main() {
match read_username_from_file() {
Ok(username) => println!("Username: {}", username),
Err(error) => println!("Error: {}", error),
}
let text = "Hello\nWorld";
match last_char_of_first_line(text) {
Some(ch) => println!("Last char: {}", ch),
None => println!("No last char found"),
}
}
# Python异常传播
def read_username_from_file_verbose():
"""传统的异常处理方式"""
try:
username_file = open("hello.txt", 'r')
except IOError as e:
raise e
try:
username = username_file.read()
username_file.close()
return username
except IOError as e:
username_file.close()
raise e
def read_username_from_file():
"""Python的惯用方式"""
with open("hello.txt", 'r') as f:
return f.read()
def read_username_from_file_with_handling():
"""带错误处理的版本"""
try:
with open("hello.txt", 'r') as f:
return f.read()
except FileNotFoundError:
raise FileNotFoundError("Username file not found")
except IOError as e:
raise IOError(f"Error reading username file: {e}")
# Python没有直接等价的?操作符,但可以用装饰器模拟
def propagate_none(func):
"""装饰器:如果任何中间步骤返回None,则返回None"""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except (AttributeError, TypeError):
return None
return wrapper
@propagate_none
def last_char_of_first_line(text):
return text.split('\n')[0][-1] if text and '\n' in text else text[-1] if text else None
def last_char_of_first_line_safe(text):
"""更安全的版本"""
if not text:
return None
lines = text.split('\n')
if not lines:
return None
first_line = lines[0]
if not first_line:
return None
return first_line[-1]
def main():
try:
username = read_username_from_file()
print(f"Username: {username}")
except IOError as error:
print(f"Error: {error}")
text = "Hello\nWorld"
last_char = last_char_of_first_line_safe(text)
if last_char:
print(f"Last char: {last_char}")
else:
print("No last char found")
if __name__ == "__main__":
main()
6.6 自定义错误类型
创建和使用自定义错误
// Rust自定义错误类型
use std::fmt;
use std::error::Error;
#[derive(Debug)]
enum CalculatorError {
DivisionByZero,
InvalidInput(String),
Overflow,
}
impl fmt::Display for CalculatorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CalculatorError::DivisionByZero => write!(f, "Division by zero"),
CalculatorError::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
CalculatorError::Overflow => write!(f, "Calculation overflow"),
}
}
}
impl Error for CalculatorError {}
struct Calculator;
impl Calculator {
fn divide(a: f64, b: f64) -> Result<f64, CalculatorError> {
if b == 0.0 {
Err(CalculatorError::DivisionByZero)
} else {
let result = a / b;
if result.is_infinite() {
Err(CalculatorError::Overflow)
} else {
Ok(result)
}
}
}
fn parse_and_add(a: &str, b: &str) -> Result<f64, CalculatorError> {
let num_a = a.parse::<f64>()
.map_err(|_| CalculatorError::InvalidInput(format!("'{}' is not a number", a)))?;
let num_b = b.parse::<f64>()
.map_err(|_| CalculatorError::InvalidInput(format!("'{}' is not a number", b)))?;
let result = num_a + num_b;
if result.is_infinite() {
Err(CalculatorError::Overflow)
} else {
Ok(result)
}
}
}
// 错误转换
#[derive(Debug)]
enum AppError {
Calculator(CalculatorError),
Io(std::io::Error),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::Calculator(err) => write!(f, "Calculator error: {}", err),
AppError::Io(err) => write!(f, "IO error: {}", err),
}
}
}
impl Error for AppError {}
impl From<CalculatorError> for AppError {
fn from(err: CalculatorError) -> AppError {
AppError::Calculator(err)
}
}
impl From<std::io::Error> for AppError {
fn from(err: std::io::Error) -> AppError {
AppError::Io(err)
}
}
fn main() {
// 测试除法
match Calculator::divide(10.0, 0.0) {
Ok(result) => println!("Division result: {}", result),
Err(error) => println!("Error: {}", error),
}
// 测试解析和加法
match Calculator::parse_and_add("10", "abc") {
Ok(result) => println!("Addition result: {}", result),
Err(error) => println!("Error: {}", error),
}
// 使用?操作符进行错误转换
fn do_calculation() -> Result<f64, AppError> {
let result = Calculator::parse_and_add("10", "20")?; // 自动转换
Ok(result * 2.0)
}
match do_calculation() {
Ok(result) => println!("Final result: {}", result),
Err(error) => println!("Application error: {}", error),
}
}
# Python自定义异常类型
class CalculatorError(Exception):
"""计算器基础异常"""
pass
class DivisionByZeroError(CalculatorError):
"""除零异常"""
def __init__(self):
super().__init__("Division by zero")
class InvalidInputError(CalculatorError):
"""无效输入异常"""
def __init__(self, message):
super().__init__(f"Invalid input: {message}")
class OverflowError(CalculatorError):
"""溢出异常"""
def __init__(self):
super().__init__("Calculation overflow")
class Calculator:
@staticmethod
def divide(a, b):
if b == 0:
raise DivisionByZeroError()
result = a / b
if not (-float('inf') < result < float('inf')):
raise OverflowError()
return result
@staticmethod
def parse_and_add(a_str, b_str):
try:
num_a = float(a_str)
except ValueError:
raise InvalidInputError(f"'{a_str}' is not a number")
try:
num_b = float(b_str)
except ValueError:
raise InvalidInputError(f"'{b_str}' is not a number")
result = num_a + num_b
if not (-float('inf') < result < float('inf')):
raise OverflowError()
return result
# 异常包装
class AppError(Exception):
"""应用程序错误包装器"""
def __init__(self, original_error):
self.original_error = original_error
super().__init__(f"Application error: {original_error}")
def main():
# 测试除法
try:
result = Calculator.divide(10.0, 0.0)
print(f"Division result: {result}")
except CalculatorError as error:
print(f"Error: {error}")
# 测试解析和加法
try:
result = Calculator.parse_and_add("10", "abc")
print(f"Addition result: {result}")
except CalculatorError as error:
print(f"Error: {error}")
# 异常包装
def do_calculation():
try:
result = Calculator.parse_and_add("10", "20")
return result * 2.0
except CalculatorError as e:
raise AppError(e)
except IOError as e:
raise AppError(e)
try:
result = do_calculation()
print(f"Final result: {result}")
except AppError as error:
print(f"Application error: {error}")
if __name__ == "__main__":
main()
6.7 实践练习
练习1:文件处理器
// Rust文件处理器
use std::fs;
use std::io;
use std::path::Path;
#[derive(Debug)]
enum FileProcessorError {
FileNotFound(String),
PermissionDenied(String),
InvalidFormat(String),
IoError(io::Error),
}
impl std::fmt::Display for FileProcessorError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
FileProcessorError::FileNotFound(path) => {
write!(f, "File not found: {}", path)
}
FileProcessorError::PermissionDenied(path) => {
write!(f, "Permission denied: {}", path)
}
FileProcessorError::InvalidFormat(msg) => {
write!(f, "Invalid format: {}", msg)
}
FileProcessorError::IoError(err) => {
write!(f, "IO error: {}", err)
}
}
}
}
impl std::error::Error for FileProcessorError {}
impl From<io::Error> for FileProcessorError {
fn from(err: io::Error) -> Self {
match err.kind() {
io::ErrorKind::NotFound => {
FileProcessorError::FileNotFound("Unknown file".to_string())
}
io::ErrorKind::PermissionDenied => {
FileProcessorError::PermissionDenied("Unknown file".to_string())
}
_ => FileProcessorError::IoError(err),
}
}
}
struct FileProcessor;
impl FileProcessor {
fn read_and_count_lines(path: &str) -> Result<usize, FileProcessorError> {
if !Path::new(path).exists() {
return Err(FileProcessorError::FileNotFound(path.to_string()));
}
let content = fs::read_to_string(path)?;
Ok(content.lines().count())
}
fn copy_file(src: &str, dst: &str) -> Result<(), FileProcessorError> {
if !Path::new(src).exists() {
return Err(FileProcessorError::FileNotFound(src.to_string()));
}
fs::copy(src, dst)?;
Ok(())
}
fn validate_json_file(path: &str) -> Result<(), FileProcessorError> {
let content = fs::read_to_string(path)?;
// 简单的JSON验证(实际项目中应该使用JSON库)
if !content.trim_start().starts_with('{') || !content.trim_end().ends_with('}') {
return Err(FileProcessorError::InvalidFormat(
"File does not appear to be valid JSON".to_string()
));
}
Ok(())
}
}
fn main() {
// 测试行数统计
match FileProcessor::read_and_count_lines("Cargo.toml") {
Ok(lines) => println!("File has {} lines", lines),
Err(error) => println!("Error reading file: {}", error),
}
// 测试文件复制
match FileProcessor::copy_file("Cargo.toml", "Cargo_backup.toml") {
Ok(()) => println!("File copied successfully"),
Err(error) => println!("Error copying file: {}", error),
}
// 测试JSON验证
match FileProcessor::validate_json_file("nonexistent.json") {
Ok(()) => println!("JSON is valid"),
Err(error) => println!("JSON validation error: {}", error),
}
}
# Python文件处理器
import os
import shutil
import json
from typing import Optional
class FileProcessorError(Exception):
"""文件处理器基础异常"""
pass
class FileNotFoundError(FileProcessorError):
def __init__(self, path):
super().__init__(f"File not found: {path}")
class PermissionDeniedError(FileProcessorError):
def __init__(self, path):
super().__init__(f"Permission denied: {path}")
class InvalidFormatError(FileProcessorError):
def __init__(self, message):
super().__init__(f"Invalid format: {message}")
class FileProcessor:
@staticmethod
def read_and_count_lines(path: str) -> int:
if not os.path.exists(path):
raise FileNotFoundError(path)
try:
with open(path, 'r', encoding='utf-8') as f:
return sum(1 for _ in f)
except PermissionError:
raise PermissionDeniedError(path)
except IOError as e:
raise FileProcessorError(f"IO error: {e}")
@staticmethod
def copy_file(src: str, dst: str) -> None:
if not os.path.exists(src):
raise FileNotFoundError(src)
try:
shutil.copy2(src, dst)
except PermissionError:
raise PermissionDeniedError(src)
except IOError as e:
raise FileProcessorError(f"IO error: {e}")
@staticmethod
def validate_json_file(path: str) -> None:
if not os.path.exists(path):
raise FileNotFoundError(path)
try:
with open(path, 'r', encoding='utf-8') as f:
json.load(f)
except json.JSONDecodeError as e:
raise InvalidFormatError(f"Invalid JSON: {e}")
except PermissionError:
raise PermissionDeniedError(path)
except IOError as e:
raise FileProcessorError(f"IO error: {e}")
def main():
# 测试行数统计
try:
lines = FileProcessor.read_and_count_lines("requirements.txt")
print(f"File has {lines} lines")
except FileProcessorError as error:
print(f"Error reading file: {error}")
# 测试文件复制
try:
FileProcessor.copy_file("requirements.txt", "requirements_backup.txt")
print("File copied successfully")
except FileProcessorError as error:
print(f"Error copying file: {error}")
# 测试JSON验证
try:
FileProcessor.validate_json_file("nonexistent.json")
print("JSON is valid")
except FileProcessorError as error:
print(f"JSON validation error: {error}")
if __name__ == "__main__":
main()
6.8 本章小结
通过本章学习,你应该掌握:
- 错误分类:可恢复错误(Result)vs 不可恢复错误(panic!)
- Result类型:安全地处理可能失败的操作
- 错误传播:使用?操作符简化错误处理
- 自定义错误:创建特定领域的错误类型
- 错误转换:在不同错误类型间转换
与Python的关键差异:
特性 | Rust | Python |
---|---|---|
错误处理 | Result类型,编译时检查 | 异常机制,运行时处理 |
错误传播 | ?操作符,显式传播 | 自动栈展开 |
错误分类 | 可恢复/不可恢复 | 统一异常模型 |
性能 | 零成本抽象 | 异常有运行时开销 |
强制处理 | 编译器强制处理Result | 可以忽略异常 |
关键要点:
- Rust强制你处理所有可能的错误情况
- Result类型让错误处理成为类型系统的一部分
- ?操作符提供了简洁的错误传播方式
- 自定义错误类型提供更好的错误信息
下一章预告: 我们将学习Rust的特征系统和泛型,这是Rust实现多态的关键机制。