数据结构与集合
您将学到: Rust 元组 vs Python 元组、数组和切片、struct(Rust 替代类的方式)、
Vec<T>vslist、HashMap<K,V>vsdict以及用于领域建模的 newtype 模式。难度: 初级
Python 元组
Section titled “Python 元组”# Python — 元组是不可变序列point = (3.0, 4.0)x, y = point # 解包print(f"x={x}, y={y}")
# 元组可以持有混合类型record = ("Alice", 30, True)name, age, active = record
# 命名元组提高清晰度from typing import NamedTuple
class Point(NamedTuple): x: float y: float
p = Point(3.0, 4.0)print(p.x) # 命名访问Rust 元组
Section titled “Rust 元组”// Rust — 元组是固定大小、类型化、可持有混合类型let point: (f64, f64) = (3.0, 4.0);let (x, y) = point; // 解构(与 Python 解包相同)println!("x={x}, y={y}");
// 混合类型let record: (&str, i32, bool) = ("Alice", 30, true);let (name, age, active) = record;
// 通过索引访问(与 Python 不同,使用 .0 .1 .2 语法)let first = record.0; // "Alice"let second = record.1; // 30
// Python: record[0]// Rust: record.0 ← 点索引,不是括号索引何时使用元组 vs Struct
Section titled “何时使用元组 vs Struct”// 元组:快速分组、函数返回、临时值fn min_max(data: &[i32]) -> (i32, i32) { (*data.iter().min().unwrap(), *data.iter().max().unwrap())}let (lo, hi) = min_max(&[3, 1, 4, 1, 5]);
// Struct:需要命名字段、清晰意图、方法struct Point { x: f64, y: f64 }
// 经验法则:// - 2-3 个同类型字段 → 元组即可// - 需要命名字段 → 使用 struct// - 需要方法 → 使用 struct// (与 Python 相同指导:tuple vs namedtuple vs dataclass)Python 列表 vs Rust 数组
Section titled “Python 列表 vs Rust 数组”# Python — 列表是动态的、异构的numbers = [1, 2, 3, 4, 5] # 可以增长、缩小、持有混合类型numbers.append(6)mixed = [1, "two", 3.0] # 允许混合类型// Rust 有两种固定大小 vs 动态的概念:
// 1. Array — 固定大小,栈分配(无 Python 等效)let numbers: [i32; 5] = [1, 2, 3, 4, 5]; // 大小是类型的一部分!// numbers.push(6); // ❌ 数组不能增长
// 将所有元素初始化为相同值:let zeros = [0; 10]; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// 2. Slice — 数组或 Vec 的视图(类似 Python 切片,但是被借用的)let slice: &[i32] = &numbers[1..4]; // [2, 3, 4] — 一个引用,不是副本!
// Python: numbers[1:4] 创建新列表(副本)// Rust: &numbers[1..4] 创建视图(无副本、无分配)# Python 切片 — 创建副本data = [10, 20, 30, 40, 50]first_three = data[:3] # 新列表:[10, 20, 30]last_two = data[-2:] # 新列表:[40, 50]reversed_data = data[::-1] # 新列表:[50, 40, 30, 20, 10]// Rust 切片 — 创建视图(引用)let data = [10, 20, 30, 40, 50];let first_three = &data[..3]; // &[i32],视图:[10, 20, 30]let last_two = &data[3..]; // &[i32],视图:[40, 50]
// 无负索引 — 使用 .len()let last_two = &data[data.len()-2..]; // &[i32],视图:[40, 50]
// 反转:使用迭代器let reversed: Vec<i32> = data.iter().rev().copied().collect();Struct vs 类
Section titled “Struct vs 类”Python 类
Section titled “Python 类”# Python — 带 __init__、方法、属性的类from dataclasses import dataclass
@dataclassclass Rectangle: width: float height: float
def area(self) -> float: return self.width * self.height
def perimeter(self) -> float: return 2.0 * (self.width + self.height)
def scale(self, factor: float) -> "Rectangle": return Rectangle(self.width * factor, self.height * factor)
def __str__(self) -> str: return f"Rectangle({self.width} x {self.height})"
r = Rectangle(10.0, 5.0)print(r.area()) # 50.0print(r) # Rectangle(10.0 x 5.0)Rust Struct
Section titled “Rust Struct”// Rust — struct + impl 块(无继承!)#[derive(Debug, Clone)]struct Rectangle { width: f64, height: f64,}
impl Rectangle { // "构造函数" — 关联函数(无 self) fn new(width: f64, height: f64) -> Self { Rectangle { width, height } // 字段简写当名称匹配时 }
fn area(&self) -> f64 { self.width * self.height }
fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) }
fn scale(&self, factor: f64) -> Rectangle { Rectangle::new(self.width * factor, self.height * factor) }}
// Display trait = Python 的 __str__impl std::fmt::Display for Rectangle { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Rectangle({} x {})", self.width, self.height) }}
fn main() { let r = Rectangle::new(10.0, 5.0); println!("{}", r.area()); // 50.0 println!("{}", r); // Rectangle(10 x 5)}flowchart LR subgraph Python ["Python 对象(堆)"] PH["PyObject Header<br/>(refcount + type ptr)"] --> PW["width: float obj"] PH --> PHT["height: float obj"] PH --> PD["__dict__"] end subgraph Rust ["Rust Struct(栈)"] RW["width: f64<br/>(8 bytes)"] --- RH["height: f64<br/>(8 bytes)"] end style Python fill:#ffeeba style Rust fill:#d4edda内存洞察:Python
Rectangle对象有 56 字节头 + 独立堆分配的浮点对象。RustRectangle在栈上正好是 16 字节——无间接寻址,无 GC 压力。另请参阅:第 10 章 — Trait 与泛型 涵盖为您的 struct 实现 trait,如
Display、Debug和运算符重载。
关键映射:Python 特殊方法 → Rust Trait
Section titled “关键映射:Python 特殊方法 → Rust Trait”| Python | Rust | 目的 |
|---|---|---|
__str__ | impl Display | 人类可读字符串 |
__repr__ | #[derive(Debug)] | 调试表示 |
__eq__ | #[derive(PartialEq)] | 相等比较 |
__hash__ | #[derive(Hash)] | 可哈希(用于 dict 键 / HashSet) |
__lt__, __le__ 等 | #[derive(PartialOrd, Ord)] | 排序 |
__add__ | impl Add | + 运算符 |
__iter__ | impl Iterator | 迭代 |
__len__ | .len() 方法 | 长度 |
__enter__/__exit__ | RAII + impl Drop | 自动清理;无上下文管理器两阶段协议的直接等效 |
__init__ | fn new()(约定) | 构造函数 |
__getitem__ | impl Index | 使用 [] 索引 |
__contains__ | .contains() 方法 | in 运算符 |
无继承——组合代替
Section titled “无继承——组合代替”# Python — 继承class Animal: def __init__(self, name: str): self.name = name def speak(self) -> str: raise NotImplementedError
class Dog(Animal): def speak(self) -> str: return f"{self.name} says Woof!"
class Cat(Animal): def speak(self) -> str: return f"{self.name} says Meow!"// Rust — trait + 组合(无继承)trait Animal { fn name(&self) -> &str; fn speak(&self) -> String;}
struct Dog { name: String }struct Cat { name: String }
impl Animal for Dog { fn name(&self) -> &str { &self.name } fn speak(&self) -> String { format!("{} says Woof!", self.name) }}
impl Animal for Cat { fn name(&self) -> &str { &self.name } fn speak(&self) -> String { format!("{} says Meow!", self.name) }}
// 使用 trait 对象实现多态(类似 Python 的鸭子类型):fn animal_roll_call(animals: &[&dyn Animal]) { for a in animals { println!("{}", a.speak()); }}心智模型:Python 说”继承行为”。Rust 说”实现契约”。 结果类似,但 Rust 避免了菱形继承问题和脆弱基类问题。
Vec vs list
Section titled “Vec vs list”Vec<T> 是 Rust 的可增长、堆分配数组——最接近 Python list 的等效物。
# Pythonnumbers = [1, 2, 3]empty = []repeated = [0] * 10from_range = list(range(1, 6))// Rustlet numbers = vec![1, 2, 3]; // vec! 宏(类似列表字面量)let empty: Vec<i32> = Vec::new(); // 空 vec(需要类型注解)let repeated = vec![0; 10]; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]let from_range: Vec<i32> = (1..6).collect(); // [1, 2, 3, 4, 5]# Python 列表操作nums = [1, 2, 3]nums.append(4) # [1, 2, 3, 4]nums.extend([5, 6]) # [1, 2, 3, 4, 5, 6]nums.insert(0, 0) # [0, 1, 2, 3, 4, 5, 6]last = nums.pop() # 6, nums = [0, 1, 2, 3, 4, 5]length = len(nums) # 6nums.sort() # 原地排序sorted_copy = sorted(nums) # 新排序列表nums.reverse() # 原地反转contains = 3 in nums # Trueindex = nums.index(3) # 第一个 3 的索引// Rust Vec 操作let mut nums = vec![1, 2, 3];nums.push(4); // [1, 2, 3, 4]nums.extend([5, 6]); // [1, 2, 3, 4, 5, 6]nums.insert(0, 0); // [0, 1, 2, 3, 4, 5, 6]let last = nums.pop(); // Some(6), nums = [0, 1, 2, 3, 4, 5]let length = nums.len(); // 6nums.sort(); // 原地排序let mut sorted_copy = nums.clone();sorted_copy.sort(); // 对克隆排序nums.reverse(); // 原地反转let contains = nums.contains(&3); // truelet index = nums.iter().position(|&x| x == 3); // Some(index) 或 None| Python | Rust | 备注 |
|---|---|---|
lst.append(x) | vec.push(x) | |
lst.extend(other) | vec.extend(other) | |
lst.pop() | vec.pop() | 返回 Option<T> |
lst.insert(i, x) | vec.insert(i, x) | |
lst.remove(x) | vec.iter().position(|v| v == &x).map(|i| vec.remove(i)) | 只移除第一个匹配(使用 retain 移除所有) |
del lst[i] | vec.remove(i) | 返回移除的元素 |
len(lst) | vec.len() | |
x in lst | vec.contains(&x) | |
lst.sort() | vec.sort() | |
sorted(lst) | 克隆 + 排序,或迭代器 | |
lst[i] | vec[i] | 越界时 panic |
lst.get(i, default) | vec.get(i) | 返回 Option<&T> |
lst[1:3] | &vec[1..3] | 返回切片(无副本) |
HashMap vs dict
Section titled “HashMap vs dict”HashMap<K, V> 是 Rust 的哈希映射——等效于 Python 的 dict。
创建 HashMap
Section titled “创建 HashMap”# Pythonscores = {"Alice": 100, "Bob": 85}empty = {}from_pairs = dict([("x", 1), ("y", 2)])comprehension = {k: v for k, v in zip(keys, values)}// Rustuse std::collections::HashMap;
let scores = HashMap::from([("Alice", 100), ("Bob", 85)]);let empty: HashMap<String, i32> = HashMap::new();let from_pairs: HashMap<&str, i32> = [("x", 1), ("y", 2)].into_iter().collect();let comprehension: HashMap<_, _> = keys.iter().zip(values.iter()).collect();# Python dict 操作d = {"a": 1, "b": 2}d["c"] = 3 # 插入val = d["a"] # 1(缺失时 KeyError)val = d.get("z", 0) # 0(缺失时默认值)del d["b"] # 移除exists = "a" in d # Truekeys = list(d.keys()) # ["a", "c"]values = list(d.values()) # [1, 3]items = list(d.items()) # [("a", 1), ("c", 3)]length = len(d) # 2
# setdefault / defaultdictfrom collections import defaultdictword_count = defaultdict(int)for word in words: word_count[word] += 1// Rust HashMap 操作use std::collections::HashMap;
let mut d = HashMap::new();d.insert("a", 1);d.insert("b", 2);d.insert("c", 3); // 插入或覆盖
let val = d["a"]; // 1(缺失时 panic)let val = d.get("z").copied().unwrap_or(0); // 0(安全访问)d.remove("b"); // 移除let exists = d.contains_key("a"); // truelet keys: Vec<_> = d.keys().collect();let values: Vec<_> = d.values().collect();let length = d.len();
// entry API = Python 的 setdefault / defaultdict 模式let mut word_count: HashMap<&str, i32> = HashMap::new();for word in words { *word_count.entry(word).or_insert(0) += 1;}| Python | Rust | 备注 |
|---|---|---|
d[key] = val | d.insert(key, val) | 返回 Option<V>(旧值) |
d[key] | d[&key] | 缺失时 panic |
d.get(key) | d.get(&key) | 返回 Option<&V> |
d.get(key, default) | d.get(&key).unwrap_or(&default) | |
key in d | d.contains_key(&key) | |
del d[key] | d.remove(&key) | 返回 Option<V> |
d.keys() | d.keys() | 迭代器 |
d.values() | d.values() | 迭代器 |
d.items() | d.iter() | (&K, &V) 的迭代器 |
len(d) | d.len() | |
d.update(other) | d.extend(other) | |
defaultdict(int) | .entry().or_insert(0) | Entry API |
d.setdefault(k, v) | d.entry(k).or_insert(v) | Entry API |
| Python | Rust | 备注 |
|---|---|---|
set() | HashSet<T> | use std::collections::HashSet; |
collections.deque | VecDeque<T> | use std::collections::VecDeque; |
heapq | BinaryHeap<T> | 默认最大堆 |
collections.OrderedDict | IndexMap(crate) | HashMap 不保持顺序 |
sortedcontainers.SortedList | BTreeSet<T> / BTreeMap<K,V> | 基于树、有序 |
🏋️ 练习:词频计数器(点击展开)
挑战:编写一个函数,接受 &str 句子并返回 HashMap<String, usize> 的词频(不区分大小写)。在 Python 中这是 Counter(s.lower().split())。翻译成 Rust。
🔑 答案
use std::collections::HashMap;
fn word_frequencies(text: &str) -> HashMap<String, usize> { let mut counts = HashMap::new(); for word in text.split_whitespace() { let key = word.to_lowercase(); *counts.entry(key).or_insert(0) += 1; } counts}
fn main() { let text = "the quick brown fox jumps over the lazy fox"; let freq = word_frequencies(text); for (word, count) in &freq { println!("{word}: {count}"); }}关键收获:HashMap::entry().or_insert() 是 Python defaultdict 或 Counter 的 Rust 等效物。* 解引用是必需的,因为 or_insert 返回 &mut usize。