Rust 编程实战练习
Rust 编程实战练习
本练习集要求你手写完整代码,而非填空。每个练习都是独立的编程任务,难度递进。
第一部分:题目
练习 1:FizzBuzz(基础控制流)
要求:编写程序,打印 1 到 100 的数字,但:
- 能被 3 整除打印 "Fizz"
- 能被 5 整除打印 "Buzz"
- 能同时被 3 和 5 整除打印 "FizzBuzz"
- 其他情况打印数字本身
预期输出(部分):
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
练习 2:温度转换(函数与输入)
要求:实现温度转换程序:
- 编写函数
celsius_to_fahrenheit(c: f64) -> f64:摄氏转华氏 - 编写函数
fahrenheit_to_celsius(f: f64) -> f64:华氏转摄氏 - 主函数中验证:0°C = 32°F,100°C = 212°F
公式:
- F = C × 9/5 + 32
- C = (F - 32) × 5/9
练习 3:回文检测(字符串处理)
要求:实现函数 is_palindrome(s: &str) -> bool,判断字符串是否为回文(忽略大小写和空格)。
测试用例:
assert!(is_palindrome("racecar"));
assert!(is_palindrome("A man a plan a canal Panama"));
assert!(!is_palindrome("hello"));
练习 4:统计单词频率(所有权与 HashMap)
要求:实现函数 word_frequency(text: &str) -> HashMap<String, u32>,统计文本中每个单词的出现次数。
测试用例:
let text = "hello world hello rust world world";
let freq = word_frequency(text);
assert_eq!(freq.get("hello"), Some(&2));
assert_eq!(freq.get("world"), Some(&3));
assert_eq!(freq.get("rust"), Some(&1));
练习 5:实现 Vec 的基本操作(结构体与方法)
要求:实现一个简化版的动态数组 MyVec<T>,支持以下操作:
struct MyVec<T> {
// 你需要决定内部数据结构
}
impl<T> MyVec<T> {
fn new() -> Self;
fn push(&mut self, item: T);
fn pop(&mut self) -> Option<T>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn get(&self, index: usize) -> Option<&T>;
}
测试用例:
let mut vec = MyVec::new();
assert!(vec.is_empty());
vec.push(1);
vec.push(2);
vec.push(3);
assert_eq!(vec.len(), 3);
assert_eq!(vec.get(1), Some(&2));
assert_eq!(vec.pop(), Some(3));
assert_eq!(vec.len(), 2);
练习 6:二叉树遍历(枚举与递归)
要求:实现二叉树及其遍历方法。
enum BinaryTree<T> {
Empty,
NonEmpty(Box<TreeNode<T>>),
}
struct TreeNode<T> {
value: T,
left: BinaryTree<T>,
right: BinaryTree<T>,
}
实现以下方法:
insert(value: T)- 插入值(假设是二叉搜索树)in_order()- 中序遍历,返回值的向量
练习 7:表达式求值(模式匹配与错误处理)
要求:实现一个简单的算术表达式求值器,支持加减乘除。
enum Expr {
Number(i64),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
}
fn eval(expr: &Expr) -> Result<i64, String> {
// 返回计算结果,除零返回 Err
}
测试用例:
// 表示: (2 + 3) * 4 - 10 / 2 = 15
let expr = Expr::Sub(
Box::new(Expr::Mul(
Box::new(Expr::Add(Box::new(Expr::Number(2)), Box::new(Expr::Number(3)))),
Box::new(Expr::Number(4)),
)),
Box::new(Expr::Div(Box::new(Expr::Number(10)), Box::new(Expr::Number(2)))),
);
assert_eq!(eval(&expr), Ok(15));
// 除零测试
let div_zero = Expr::Div(Box::new(Expr::Number(1)), Box::new(Expr::Number(0)));
assert!(eval(&div_zero).is_err());
练习 8:泛型栈(泛型与 Trait)
要求:实现一个泛型栈 Stack<T>,并为其实现 Display trait。
struct Stack<T> {
// 内部结构
}
impl<T> Stack<T> {
fn new() -> Self;
fn push(&mut self, item: T);
fn pop(&mut self) -> Option<T>;
fn peek(&self) -> Option<&T>;
}
impl<T: std::fmt::Display> std::fmt::Display for Stack<T> {
// 格式化输出,从底到顶显示元素
}
测试用例:
let mut stack = Stack::new();
stack.push(1);
stack.push(2);
stack.push(3);
println!("{}", stack); // 输出: [1, 2, 3]
assert_eq!(stack.pop(), Some(3));
assert_eq!(stack.peek(), Some(&2));
练习 9:并行下载模拟(闭包与迭代器)
要求:模拟并行下载多个文件,使用闭包和迭代器。
struct DownloadTask {
url: String,
size: u64, // 文件大小(模拟)
}
fn simulate_download(tasks: Vec<DownloadTask>) -> Vec<(String, bool)> {
// 模拟下载每个任务
// 假设:如果 URL 包含 "error" 则失败
// 返回 (url, success) 的列表
}
使用迭代器方法完成:
- 统计成功的下载数量
- 获取所有失败的 URL
- 计算总下载大小(仅成功的)
测试用例:
let tasks = vec![
DownloadTask { url: String::from("file1.txt"), size: 100 },
DownloadTask { url: String::from("error.txt"), size: 200 },
DownloadTask { url: String::from("file2.txt"), size: 150 },
];
let results = simulate_download(tasks);
// 使用迭代器处理结果...
练习 10:简单的 JSON 解析器(综合练习)
要求:实现一个简化版的 JSON 解析器,支持以下类型:
#[derive(Debug, PartialEq)]
enum JsonValue {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<JsonValue>),
Object(std::collections::HashMap<String, JsonValue>),
}
fn parse_json(input: &str) -> Result<JsonValue, String> {
// 解析 JSON 字符串
}
测试用例:
assert_eq!(parse_json("null"), Ok(JsonValue::Null));
assert_eq!(parse_json("true"), Ok(JsonValue::Bool(true)));
assert_eq!(parse_json("42"), Ok(JsonValue::Number(42.0)));
assert_eq!(parse_json("\"hello\""), Ok(JsonValue::String(String::from("hello"))));
练习 11:命令行参数解析(错误处理与 Option)
要求:实现一个简单的命令行计算器,解析命令行参数并执行计算。
程序调用方式:cargo run -- <num1> <op> <num2>
示例:
cargo run -- 10 + 5 # 输出: 15
cargo run -- 10 / 2 # 输出: 5
cargo run -- 10 / 0 # 输出: 错误: 除数不能为零
cargo run -- 10 % 5 # 输出: 错误: 不支持的操作符
练习 12:实现 Result 组合子(高级错误处理)
要求:为自定义的 MyResult<T, E> 实现常用的组合子方法。
enum MyResult<T, E> {
Ok(T),
Err(E),
}
impl<T, E> MyResult<T, E> {
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> MyResult<U, E>;
fn map_err<F, F2: FnOnce(E) -> F2>(self, f: F2) -> MyResult<T, F>;
fn and_then<U, F: FnOnce(T) -> MyResult<U, E>>(self, f: F) -> MyResult<U, E>;
fn unwrap_or(self, default: T) -> T;
}
测试用例:
let result: MyResult<i32, &str> = MyResult::Ok(5);
assert_eq!(result.map(|x| x * 2), MyResult::Ok(10));
let err: MyResult<i32, &str> = MyResult::Err("error");
assert_eq!(err.map(|x| x * 2), MyResult::Err("error"));
练习 13:实现智能指针 MyBox(Deref 与 Drop)
要求:实现一个简化版的 Box,支持解引用和自动释放。
struct MyBox<T> {
// 内部结构
}
impl<T> MyBox<T> {
fn new(value: T) -> Self;
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target;
}
impl<T> Drop for MyBox<T> {
fn drop(&mut self);
}
测试用例:
let x = MyBox::new(5);
assert_eq!(*x, 5);
let s = MyBox::new(String::from("hello"));
assert_eq!(&*s, "hello");
// 离开作用域时自动打印 "Dropping MyBox"
练习 14:工作线程池(Arc 与 Mutex)
要求:实现一个简单的线程池,可以并发执行任务。
use std::sync::{Arc, Mutex};
use std::thread;
struct ThreadPool {
// 内部结构
}
impl ThreadPool {
fn new(size: usize) -> Self;
fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static;
}
impl Drop for ThreadPool {
fn drop(&mut self);
}
测试用例:
let pool = ThreadPool::new(4);
for i in 0..8 {
pool.execute(move || {
println!("任务 {} 在线程 {:?} 中执行", i, thread::current().id());
});
}
// 等待所有任务完成
练习 15:链表实现(所有权与 Option)
要求:实现一个泛型链表,支持基本的 CRUD 操作。
struct LinkedList<T> {
head: Option<Box<Node<T>>>,
}
struct Node<T> {
value: T,
next: Option<Box<Node<T>>>,
}
impl<T> LinkedList<T> {
fn new() -> Self;
fn push(&mut self, value: T); // 头部插入
fn pop(&mut self) -> Option<T>; // 头部删除
fn len(&self) -> usize;
fn iter(&self) -> Iter<T>; // 返回迭代器
}
// 迭代器
struct Iter<'a, T> {
next: Option<&'a Node<T>>,
}
测试用例:
let mut list = LinkedList::new();
list.push(1);
list.push(2);
list.push(3);
assert_eq!(list.len(), 3);
assert_eq!(list.pop(), Some(3));
assert_eq!(list.pop(), Some(2));
// 遍历: 1
练习 16:字符串切片与生命周期(生命周期基础)
要求:实现一个函数,返回字符串中第一个单词。
fn first_word(s: &str) -> ??? {
// 返回第一个单词的切片
// 单词由空格分隔
}
测试用例:
let s = String::from("hello world");
let word = first_word(&s);
assert_eq!(word, "hello");
let s = "hello world";
let word = first_word(s);
assert_eq!(word, "hello");
let s = "hello";
let word = first_word(s);
assert_eq!(word, "hello");
let s = "";
let word = first_word(s);
assert_eq!(word, "");
思考:返回类型应该是什么?为什么需要生命周期标注?
练习 17:结构体中的生命周期(生命周期进阶)
要求:实现一个 TextAnalyzer 结构体,存储文本引用并提供分析方法。
struct TextAnalyzer<'a> {
text: &'a str,
}
impl<'a> TextAnalyzer<'a> {
fn new(text: &'a str) -> Self;
fn word_count(&self) -> usize;
fn longest_word(&self) -> Option<&'a str>; // 返回生命周期与 text 相同
fn contains(&self, word: &str) -> bool;
}
测试用例:
let text = "the quick brown fox jumps over the lazy dog";
let analyzer = TextAnalyzer::new(text);
assert_eq!(analyzer.word_count(), 9);
assert_eq!(analyzer.longest_word(), Some("jumps"));
assert!(analyzer.contains("fox"));
assert!(!analyzer.contains("cat"));
练习 18:多个生命周期参数
要求:实现一个函数,返回两个字符串切片中较长的那个。
fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
// 返回较长的字符串
}
进阶:实现一个函数,将两个字符串拼接并返回。
fn combine_and_process<'a, 'b>(s1: &'a str, s2: &'b str) -> String {
// 返回新字符串,不依赖输入的生命周期
}
测试用例:
let s1 = String::from("hello");
let s2 = String::from("world!");
let result = longer(&s1, &s2);
assert_eq!(result, "world!");
// 下面的代码应该能编译
let s1 = String::from("long string");
let result;
{
let s2 = String::from("short");
result = longer(&s1, &s2);
}
println!("较长的是: {}", result); // 应该输出 "long string"
练习 19:Trait 对象与动态分发
要求:使用 trait 对象实现一个简单的绘图系统。
trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
fn name(&self) -> &str;
}
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
struct Triangle { a: f64, b: f64, c: f64 }
// 实现 Shape trait
fn total_area(shapes: &[Box<dyn Shape>]) -> f64 {
// 计算所有形状的总面积
}
fn largest_shape<'a>(shapes: &'a [Box<dyn Shape>]) -> Option<&'a Box<dyn Shape>> {
// 找出面积最大的形状
}
测试用例:
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 1.0 }),
Box::new(Rectangle { width: 2.0, height: 3.0 }),
Box::new(Triangle { a: 3.0, b: 4.0, c: 5.0 }),
];
println!("总面积: {}", total_area(&shapes));
println!("最大形状: {}", largest_shape(&shapes).unwrap().name());
练习 20:关联类型
要求:实现一个容器 trait,使用关联类型定义存储的元素类型。
trait Container {
type Item;
fn new() -> Self;
fn insert(&mut self, item: Self::Item);
fn remove(&mut self) -> Option<Self::Item>;
fn len(&self) -> usize;
}
// 为 Vec<T> 实现这个 trait(使用包装器)
struct VecContainer<T> {
data: Vec<T>,
}
// 为 LinkedList 实现这个 trait
struct LinkedContainer<T> {
// 自己实现或使用之前的 LinkedList
}
测试用例:
fn test_container<C: Container<Item=i32>>() {
let mut c = C::new();
assert_eq!(c.len(), 0);
c.insert(1);
c.insert(2);
assert_eq!(c.len(), 2);
assert_eq!(c.remove(), Some(2));
assert_eq!(c.remove(), Some(1));
assert_eq!(c.remove(), None);
}
test_container::<VecContainer<i32>>();
练习 21:From/Into 类型转换
要求:为自定义类型实现 From trait,实现类型间的转换。
struct Celsius(f64);
struct Fahrenheit(f64);
// 实现 From<Fahrenheit> for Celsius
// 实现 From<Celsius> for Fahrenheit
struct Kilometers(f64);
struct Miles(f64);
// 实现 From<Miles> for Kilometers
// 实现 From<Kilometers> for Miles
测试用例:
let c = Celsius(0.0);
let f: Fahrenheit = c.into();
assert_eq!(f.0, 32.0);
let f = Fahrenheit(212.0);
let c: Celsius = f.into();
assert_eq!(c.0, 100.0);
let km = Kilometers(1.0);
let miles: Miles = km.into();
assert!((miles.0 - 0.621371).abs() < 0.0001);
练习 22:操作符重载
要求:为复数类型实现算术操作符重载。
use std::ops::{Add, Sub, Mul, Neg};
#[derive(Debug, Clone, Copy, PartialEq)]
struct Complex {
real: f64,
imag: f64,
}
impl Complex {
fn new(real: f64, imag: f64) -> Self {
Self { real, imag }
}
}
// 实现 Add, Sub, Mul, Neg
// (a + bi) + (c + di) = (a+c) + (b+d)i
// (a + bi) - (c + di) = (a-c) + (b-d)i
// (a + bi) * (c + di) = (ac-bd) + (ad+bc)i
// -(a + bi) = -a + (-b)i
测试用例:
let a = Complex::new(1.0, 2.0);
let b = Complex::new(3.0, 4.0);
assert_eq!(a + b, Complex::new(4.0, 6.0));
assert_eq!(a - b, Complex::new(-2.0, -2.0));
assert_eq!(a * b, Complex::new(-5.0, 10.0));
assert_eq!(-a, Complex::new(-1.0, -2.0));
练习 23:宏基础
要求:实现几个实用的宏。
// 1. 实现一个简化的 vec! 宏
macro_rules! my_vec {
// 你的实现
}
// 2. 实现一个打印变量名和值的宏
macro_rules! debug_var {
// 用法: debug_var!(x, y, z)
// 输出: x = 1, y = 2, z = 3
}
// 3. 实现一个 hashmap! 宏
macro_rules! hashmap {
// 用法: hashmap!("a" => 1, "b" => 2)
}
测试用例:
let v = my_vec![1, 2, 3, 4, 5];
assert_eq!(v, vec![1, 2, 3, 4, 5]);
let x = 10;
let name = "rust";
debug_var!(x, name); // 输出: x = 10, name = "rust"
let map = hashmap!("a" => 1, "b" => 2);
assert_eq!(map.get("a"), Some(&1));
练习 24:声明式宏进阶
要求:实现一个 DSL(领域特定语言)来描述 HTML 结构。
html! {
html {
head {
title { "我的页面" }
}
body {
div (class="container") {
h1 { "标题" }
p { "这是一段文字" }
ul {
li { "项目1" }
li { "项目2" }
}
}
}
}
}
// 输出:
// <html><head><title>我的页面</title></head><body><div class="container"><h1>标题</h1><p>这是一段文字</p><ul><li>项目1</li><li>项目2</li></ul></div></body></html>
练习 25:生产者-消费者模式(Channel)
要求:使用 std::sync::mpsc 实现生产者-消费者模式。
use std::sync::mpsc;
use std::thread;
fn producer_consumer_example() {
// 创建通道
// 启动多个生产者线程
// 启动消费者线程
// 生产者发送 0-9 的数字
// 消费者计算接收到的数字的平方和
}
预期输出:
生产者 1 发送: 0
生产者 1 发送: 1
生产者 2 发送: 2
...
消费者接收: 0, 当前平方和: 0
消费者接收: 1, 当前平方和: 1
...
最终平方和: 285
练习 26:读写锁 RwLock
要求:实现一个线程安全的缓存系统,使用 RwLock 允许多读单写。
use std::sync::RwLock;
use std::collections::HashMap;
struct Cache<K, V> {
data: RwLock<HashMap<K, V>>,
}
impl<K: Eq + std::hash::Hash + Clone, V: Clone> Cache<K, V> {
fn new() -> Self;
fn get(&self, key: &K) -> Option<V>;
fn insert(&self, key: K, value: V);
fn remove(&self, key: &K) -> Option<V>;
fn len(&self) -> usize;
}
测试用例:
use std::thread;
let cache = Arc::new(Cache::new());
// 多线程写入
let mut handles = vec![];
for i in 0..5 {
let cache = Arc::clone(&cache);
handles.push(thread::spawn(move || {
cache.insert(i, i * 10);
}));
}
for h in handles { h.join().unwrap(); }
// 多线程读取
let mut handles = vec![];
for i in 0..5 {
let cache = Arc::clone(&cache);
handles.push(thread::spawn(move || {
if let Some(v) = cache.get(&i) {
println!("key {} = {}", i, v);
}
}));
}
练习 27:Cow 写时复制
要求:使用 Cow 优化字符串处理,避免不必要的复制。
use std::borrow::Cow;
// 实现一个函数,将字符串中的敏感词替换为 ***
// 如果字符串不需要修改,返回原字符串的引用
// 如果需要修改,返回新的字符串
fn censor<'a>(input: &'a str, banned_words: &[&str]) -> Cow<'a, str> {
// 如果没有敏感词,返回引用
// 如果有敏感词,返回新字符串
}
测试用例:
let result = censor("hello world", &["bad", "evil"]);
assert!(matches!(result, Cow::Borrowed(_)));
assert_eq!(result, "hello world");
let result = censor("hello bad world", &["bad", "evil"]);
assert!(matches!(result, Cow::Owned(_)));
assert_eq!(result, "hello *** world");
练习 28:Default trait 与 Builder 模式
要求:为一个配置结构体实现 Default trait 和 Builder 模式。
#[derive(Debug)]
struct ServerConfig {
host: String,
port: u16,
max_connections: usize,
timeout_seconds: u64,
enable_ssl: bool,
}
impl Default for ServerConfig {
fn default() -> Self {
// 提供合理的默认值
}
}
struct ServerConfigBuilder {
config: ServerConfig,
}
impl ServerConfigBuilder {
fn new() -> Self;
fn host(mut self, host: impl Into<String>) -> Self;
fn port(mut self, port: u16) -> Self;
fn max_connections(mut self, max: usize) -> Self;
fn timeout(mut self, seconds: u64) -> Self;
fn ssl(mut self, enable: bool) -> Self;
fn build(self) -> ServerConfig;
}
测试用例:
let config = ServerConfig::default();
assert_eq!(config.host, "localhost");
assert_eq!(config.port, 8080);
let config = ServerConfigBuilder::new()
.host("example.com")
.port(443)
.ssl(true)
.build();
assert_eq!(config.host, "example.com");
assert_eq!(config.enable_ssl, true);
练习 29:类型状态模式
要求:使用类型系统实现状态机,编译期保证状态转换正确性。
// 一个简单的连接状态机
// Unconnected -> Connecting -> Connected -> Disconnected
struct Unconnected;
struct Connecting;
struct Connected;
struct Disconnected;
struct Connection<State> {
address: String,
_state: PhantomData<State>,
}
impl Connection<Unconnected> {
fn new(address: String) -> Self;
fn connect(self) -> Connection<Connecting>;
}
impl Connection<Connecting> {
fn wait_for_response(self) -> Result<Connection<Connected>, Connection<Unconnected>>;
}
impl Connection<Connected> {
fn send(&self, data: &str);
fn disconnect(self) -> Connection<Disconnected>;
}
测试用例:
let conn = Connection::<Unconnected>::new("127.0.0.1:8080".to_string());
// conn.send("hello"); // 编译错误!未连接不能发送
let conn = conn.connect();
let conn = conn.wait_for_response().unwrap();
conn.send("hello"); // OK
let conn = conn.disconnect();
// conn.send("hello"); // 编译错误!已断开
练习 30:Newtype 模式与类型安全
要求:使用 Newtype 模式实现类型安全的 ID 系统,防止混淆不同类型的 ID。
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct UserId(u64);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct ProductId(u64);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct OrderId(u64);
struct User { id: UserId, name: String }
struct Product { id: ProductId, name: String, price: f64 }
struct Order { id: OrderId, user_id: UserId, product_id: ProductId, quantity: u32 }
// 实现 From 和 Display
测试用例:
let user_id = UserId::new(1);
let product_id = ProductId::new(1);
// user_id == product_id // 编译错误!类型不同
let order = Order {
id: OrderId::new(100),
user_id: user_id.clone(),
product_id: product_id.clone(),
quantity: 2,
};
练习 31:异步编程基础
要求:使用 async/await 实现异步任务。
// 需要引入 tokio 或 async-std
// Cargo.toml: tokio = { version = "1", features = ["full"] }
use std::time::Duration;
async fn fetch_user(id: u32) -> String {
// 模拟网络延迟
// 返回用户名
}
async fn fetch_posts(user_id: u32) -> Vec<String> {
// 模拟网络延迟
// 返回帖子列表
}
async fn fetch_comments(post_id: u32) -> Vec<String> {
// 模拟网络延迟
// 返回评论列表
}
// 并发获取多个用户
async fn fetch_all_users(ids: Vec<u32>) -> Vec<String>;
// 顺序获取用户及其帖子
async fn fetch_user_with_posts(user_id: u32) -> (String, Vec<String>);
练习 32:迭代器自定义(实现 Iterator trait)
要求:实现自定义迭代器,生成斐波那契数列。
struct Fibonacci {
// 状态
}
impl Fibonacci {
fn new() -> Self;
}
impl Iterator for Fibonacci {
type Item = u64;
fn next(&mut self) -> Option<Self::Item>;
}
// 实现一个范围迭代器
struct Range {
start: i32,
end: i32,
}
impl Iterator for Range {
type Item = i32;
fn next(&mut self) -> Option<Self::Item>;
}
测试用例:
let fib: Vec<u64> = Fibonacci::new().take(10).collect();
assert_eq!(fib, vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34]);
let range: Vec<i32> = Range { start: 1, end: 5 }.collect();
assert_eq!(range, vec![1, 2, 3, 4]);
练习 33:双向链表(双向迭代器)
要求:实现双向链表及其双向迭代器。
struct DoublyLinkedList<T> {
head: Option<*mut Node<T>>,
tail: Option<*mut Node<T>>,
len: usize,
}
struct Node<T> {
value: T,
prev: Option<*mut Node<T>>,
next: Option<*mut Node<T>>,
}
impl<T> DoublyLinkedList<T> {
fn new() -> Self;
fn push_front(&mut self, value: T);
fn push_back(&mut self, value: T);
fn pop_front(&mut self) -> Option<T>;
fn pop_back(&mut self) -> Option<T>;
fn len(&self) -> usize;
}
// 双向迭代器
struct Iter<'a, T> {
current: Option<*mut Node<T>>,
_marker: PhantomData<&'a T>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item>;
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn next_back(&mut self) -> Option<Self::Item>;
}
练习 34:序列化与反序列化(手动实现)
要求:不使用 serde,手动实现简单的序列化和反序列化。
trait Serializable {
fn serialize(&self) -> String;
}
trait Deserializable: Sized {
fn deserialize(s: &str) -> Result<Self, String>;
}
// 为基本类型实现
impl Serializable for i32 { ... }
impl Serializable for String { ... }
impl Serializable for bool { ... }
// 为结构体实现
struct Person {
name: String,
age: i32,
active: bool,
}
// 序列化格式: "name:张三,age:25,active:true"
练习 35:内存池(unsafe Rust)
要求:实现一个简单的内存池,预分配内存,减少频繁分配。
struct MemoryPool<T> {
data: Vec<Option<T>>,
free_indices: Vec<usize>,
}
impl<T> MemoryPool<T> {
fn new(capacity: usize) -> Self;
fn allocate(&mut self, value: T) -> Option<usize>;
fn get(&self, index: usize) -> Option<&T>;
fn get_mut(&mut self, index: usize) -> Option<&mut T>;
fn deallocate(&mut self, index: usize);
fn len(&self) -> usize;
}
// 带句柄的安全版本
struct Handle { index: usize, generation: u64 }
struct GenerationalPool<T> {
data: Vec<Option<T>>,
generations: Vec<u64>,
free_list: Vec<usize>,
}
练习 36:模块系统(mod、pub、use)
要求:创建一个完整的模块化项目结构。
src/
├── main.rs
└── math/
├── mod.rs
├── geometry.rs
└── algebra.rs
模块内容要求:
// math/mod.rs - 公开模块,重导出子模块
pub mod geometry;
pub mod algebra;
pub use geometry::Circle;
pub use algebra::calculate;
// math/geometry.rs - 几何模块
pub struct Circle { pub radius: f64 }
pub struct Rectangle { pub width: f64, pub height: f64 }
pub fn area_circle(c: &Circle) -> f64 { ... }
// math/algebra.rs - 代数模块
pub fn calculate(a: f64, b: f64, op: char) -> Option<f64> { ... }
fn validate_input(a: f64, b: f64) -> bool { ... } // 私有
// main.rs
use math::{Circle, calculate};
练习要点:
- 实现
pub,pub(crate),pub(super)的不同可见性 - 使用
use导入,as重命名 - 实现
pub use重导出
练习 37:单元测试与集成测试
要求:为一个计算器库编写完整的测试套件。
项目结构:
calculator/
├── src/lib.rs
├── tests/integration_test.rs
└── Cargo.toml
测试要求:
- 单元测试(在
src/lib.rs中使用#[cfg(test)]) - 集成测试(在
tests/目录) - 文档测试(在文档注释中使用
```代码块) - 测试私有函数
- 使用
#[should_panic]测试 panic 情况 - 使用
#[ignore]标记耗时测试
计算器功能:
pub struct Calculator {
history: Vec<String>,
}
impl Calculator {
pub fn new() -> Self;
pub fn add(&mut self, a: i64, b: i64) -> i64;
pub fn subtract(&mut self, a: i64, b: i64) -> i64;
pub fn multiply(&mut self, a: i64, b: i64) -> i64;
pub fn divide(&mut self, a: i64, b: i64) -> Result<i64, CalcError>;
pub fn history(&self) -> &[String];
}
pub enum CalcError {
DivisionByZero,
Overflow,
}
练习 38:条件编译与特性(Features)
要求:实现一个支持多种后端的日志库,使用 features 控制编译。
Cargo.toml:
[features]
default = ["console"]
console = []
file = []
json = []
network = ["dep:reqwest"]
实现要求:
- 使用
#[cfg(feature = "xxx")]条件编译 - 使用
#[cfg(not(feature = "xxx"))] - 使用
compile_error!在无效配置时报错 - 使用条件编译提供不同的实现
练习 39:Send 和 Sync trait
要求:深入理解 Send 和 Sync,实现线程安全的类型。
练习:
- 实现一个不是
Send的类型 - 实现一个手动标记
Send的类型(使用unsafe) - 验证编译器的行为
背景:
Send:类型可以安全地在线程间移动所有权Sync:类型可以安全地在线程间共享引用(&T是Send的)
练习 40:原子操作(Atomics)
要求:使用 std::sync::atomic 实现高性能并发数据结构。
实现:
- 无锁计数器
- 自旋锁(Spin Lock)
- 无锁栈(Treiber Stack)
练习 41:Pin 与自引用结构体
要求:理解 Pin 和 Unpin,实现自引用结构体。
背景:
Pin<P>防止被指向的值被移动Unpintrait 表示类型可以安全移动(大多数类型自动实现)- 自引用结构体需要
!Unpin
要求:实现一个自引用结构体,其中某个字段指向同一结构体内的另一个字段。
练习 42:过程宏入门(derive 宏)
要求:实现一个自定义 derive 宏 #[derive(Builder)]。
目标:
#[derive(Builder)]
struct Person {
name: String,
age: u32,
}
// 自动生成:
// PersonBuilder { name: Option<String>, age: Option<u32> }
// impl PersonBuilder { fn new() -> Self; fn name(mut self, ...) -> Self; ... fn build(self) -> Result<Person, String> }
练习 43:属性宏与函数式宏
要求:实现属性宏和函数式宏。
实现:
#[log_call]- 自动记录函数调用#[timed]- 自动测量函数执行时间checked_add!(a, b)- 编译时检查整数溢出的宏
练习 44:FFI 外部函数接口
要求:实现 Rust 与 C 的互操作。
内容:
- 从 Rust 调用 C 函数
- 从 C 调用 Rust 函数
- 处理复杂数据类型(结构体、字符串)
练习 45:综合项目 - 线程安全的任务队列
要求:实现一个完整的线程安全任务队列系统,综合运用所学知识。
功能要求:
- 支持提交异步任务
- 支持获取任务结果
- 支持任务优先级
- 支持任务取消
- 支持任务超时
- 完整的错误处理
第二部分:参考答案
练习 1 答案
fn main() {
for n in 1..=100 {
match (n % 3, n % 5) {
(0, 0) => println!("FizzBuzz"),
(0, _) => println!("Fizz"),
(_, 0) => println!("Buzz"),
_ => println!("{}", n),
}
}
}
练习 2 答案
fn celsius_to_fahrenheit(c: f64) -> f64 {
c * 9.0 / 5.0 + 32.0
}
fn fahrenheit_to_celsius(f: f64) -> f64 {
(f - 32.0) * 5.0 / 9.0
}
fn main() {
assert_eq!(celsius_to_fahrenheit(0.0), 32.0);
assert_eq!(celsius_to_fahrenheit(100.0), 212.0);
assert_eq!(fahrenheit_to_celsius(32.0), 0.0);
assert_eq!(fahrenheit_to_celsius(212.0), 100.0);
println!("所有测试通过!");
}
练习 3 答案
fn is_palindrome(s: &str) -> bool {
let cleaned: String = s.to_lowercase().chars().filter(|c| !c.is_whitespace()).collect();
let reversed: String = cleaned.chars().rev().collect();
cleaned == reversed
}
fn main() {
assert!(is_palindrome("racecar"));
assert!(is_palindrome("A man a plan a canal Panama"));
assert!(!is_palindrome("hello"));
println!("所有测试通过!");
}
练习 4 答案
use std::collections::HashMap;
fn word_frequency(text: &str) -> HashMap<String, u32> {
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word.to_string()).or_insert(0);
*count += 1;
}
map
}
fn main() {
let text = "hello world hello rust world world";
let freq = word_frequency(text);
assert_eq!(freq.get("hello"), Some(&2));
assert_eq!(freq.get("world"), Some(&3));
assert_eq!(freq.get("rust"), Some(&1));
println!("所有测试通过!");
}
练习 5 答案
struct MyVec<T> {
data: Vec<T>,
}
impl<T> MyVec<T> {
fn new() -> Self {
Self { data: Vec::new() }
}
fn push(&mut self, item: T) {
self.data.push(item);
}
fn pop(&mut self) -> Option<T> {
self.data.pop()
}
fn len(&self) -> usize {
self.data.len()
}
fn is_empty(&self) -> bool {
self.data.is_empty()
}
fn get(&self, index: usize) -> Option<&T> {
self.data.get(index)
}
}
fn main() {
let mut vec = MyVec::new();
assert!(vec.is_empty());
vec.push(1);
vec.push(2);
vec.push(3);
assert_eq!(vec.len(), 3);
assert_eq!(vec.get(1), Some(&2));
assert_eq!(vec.pop(), Some(3));
assert_eq!(vec.len(), 2);
println!("所有测试通过!");
}
练习 6 答案
#[derive(Debug)]
enum BinaryTree<T> {
Empty,
NonEmpty(Box<TreeNode<T>>),
}
struct TreeNode<T> {
value: T,
left: BinaryTree<T>,
right: BinaryTree<T>,
}
impl<T: Ord> BinaryTree<T> {
fn new() -> Self {
BinaryTree::Empty
}
fn insert(&mut self, value: T) {
match self {
BinaryTree::Empty => {
*self = BinaryTree::NonEmpty(Box::new(TreeNode {
value,
left: BinaryTree::Empty,
right: BinaryTree::Empty,
}));
}
BinaryTree::NonEmpty(node) => {
if value < node.value {
node.left.insert(value);
} else if value > node.value {
node.right.insert(value);
}
}
}
}
fn in_order(&self) -> Vec<&T> {
let mut result = Vec::new();
self.in_order_helper(&mut result);
result
}
fn in_order_helper<'a>(&'a self, result: &mut Vec<&'a T>) {
match self {
BinaryTree::Empty => {}
BinaryTree::NonEmpty(node) => {
node.left.in_order_helper(result);
result.push(&node.value);
node.right.in_order_helper(result);
}
}
}
}
fn main() {
let mut tree = BinaryTree::new();
tree.insert(5);
tree.insert(3);
tree.insert(7);
tree.insert(1);
tree.insert(4);
let sorted = tree.in_order();
assert_eq!(sorted, vec![&1, &3, &4, &5, &7]);
println!("中序遍历: {:?}", sorted);
}
练习 7 答案
#[derive(Debug)]
enum Expr {
Number(i64),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Mul(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
}
fn eval(expr: &Expr) -> Result<i64, String> {
match expr {
Expr::Number(n) => Ok(*n),
Expr::Add(a, b) => {
let a = eval(a)?;
let b = eval(b)?;
Ok(a + b)
}
Expr::Sub(a, b) => {
let a = eval(a)?;
let b = eval(b)?;
Ok(a - b)
}
Expr::Mul(a, b) => {
let a = eval(a)?;
let b = eval(b)?;
Ok(a * b)
}
Expr::Div(a, b) => {
let a = eval(a)?;
let b = eval(b)?;
if b == 0 {
Err(String::from("除零错误"))
} else {
Ok(a / b)
}
}
}
}
fn main() {
// (2 + 3) * 4 - 10 / 2 = 15
let expr = Expr::Sub(
Box::new(Expr::Mul(
Box::new(Expr::Add(
Box::new(Expr::Number(2)),
Box::new(Expr::Number(3)),
)),
Box::new(Expr::Number(4)),
)),
Box::new(Expr::Div(
Box::new(Expr::Number(10)),
Box::new(Expr::Number(2)),
)),
);
assert_eq!(eval(&expr), Ok(15));
let div_zero = Expr::Div(
Box::new(Expr::Number(1)),
Box::new(Expr::Number(0)),
);
assert!(eval(&div_zero).is_err());
println!("所有测试通过!");
}
练习 8 答案
use std::fmt;
struct Stack<T> {
items: Vec<T>,
}
impl<T> Stack<T> {
fn new() -> Self {
Self { items: Vec::new() }
}
fn push(&mut self, item: T) {
self.items.push(item);
}
fn pop(&mut self) -> Option<T> {
self.items.pop()
}
fn peek(&self) -> Option<&T> {
self.items.last()
}
}
impl<T: fmt::Display> fmt::Display for Stack<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
for (i, item) in self.items.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, "]")
}
}
fn main() {
let mut stack = Stack::new();
stack.push(1);
stack.push(2);
stack.push(3);
println!("{}", stack);
assert_eq!(stack.pop(), Some(3));
assert_eq!(stack.peek(), Some(&2));
println!("所有测试通过!");
}
练习 9 答案
struct DownloadTask {
url: String,
size: u64,
}
fn simulate_download(tasks: Vec<DownloadTask>) -> Vec<(String, u64, bool)> {
tasks.into_iter()
.map(|task| {
let success = !task.url.contains("error");
(task.url, task.size, success)
})
.collect()
}
fn main() {
let tasks = vec![
DownloadTask { url: String::from("file1.txt"), size: 100 },
DownloadTask { url: String::from("error.txt"), size: 200 },
DownloadTask { url: String::from("file2.txt"), size: 150 },
DownloadTask { url: String::from("another_error.bin"), size: 300 },
];
let results = simulate_download(tasks);
// 1. 统计成功数量
let success_count = results.iter().filter(|(_, _, success)| *success).count();
println!("成功下载数: {}", success_count);
// 2. 获取失败的 URL
let failed_urls: Vec<&String> = results.iter()
.filter(|(_, _, success)| !*success)
.map(|(url, _, _)| url)
.collect();
println!("失败的 URL: {:?}", failed_urls);
// 3. 计算成功下载的总大小
let total_size: u64 = results.iter()
.filter(|(_, _, success)| *success)
.map(|(_, size, _)| *size)
.sum();
println!("总下载大小: {} bytes", total_size);
}
练习 10 答案
use std::collections::HashMap;
#[derive(Debug, PartialEq)]
enum JsonValue {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<JsonValue>),
Object(HashMap<String, JsonValue>),
}
fn parse_json(input: &str) -> Result<JsonValue, String> {
let input = input.trim();
if input == "null" {
return Ok(JsonValue::Null);
}
if input == "true" {
return Ok(JsonValue::Bool(true));
}
if input == "false" {
return Ok(JsonValue::Bool(false));
}
if input.starts_with('"') && input.ends_with('"') {
let s = &input[1..input.len()-1];
return Ok(JsonValue::String(s.to_string()));
}
if let Ok(n) = input.parse::<f64>() {
return Ok(JsonValue::Number(n));
}
if input.starts_with('[') && input.ends_with(']') {
let inner = &input[1..input.len()-1];
if inner.trim().is_empty() {
return Ok(JsonValue::Array(Vec::new()));
}
let items: Vec<JsonValue> = inner
.split(',')
.map(|s| parse_json(s.trim()))
.collect::<Result<Vec<_>, _>>()?;
return Ok(JsonValue::Array(items));
}
Err(format!("无法解析: {}", input))
}
fn main() {
assert_eq!(parse_json("null"), Ok(JsonValue::Null));
assert_eq!(parse_json("true"), Ok(JsonValue::Bool(true)));
assert_eq!(parse_json("false"), Ok(JsonValue::Bool(false)));
assert_eq!(parse_json("42"), Ok(JsonValue::Number(42.0)));
assert_eq!(parse_json("\"hello\""), Ok(JsonValue::String(String::from("hello"))));
assert_eq!(parse_json("[]"), Ok(JsonValue::Array(Vec::new())));
println!("所有测试通过!");
}
练习 11 答案
use std::env;
fn calculate(a: f64, op: &str, b: f64) -> Result<f64, String> {
match op {
"+" => Ok(a + b),
"-" => Ok(a - b),
"*" | "x" => Ok(a * b),
"/" => {
if b == 0.0 {
Err(String::from("除数不能为零"))
} else {
Ok(a / b)
}
}
_ => Err(format!("不支持的操作符: {}", op)),
}
}
fn parse_args() -> Result<(f64, String, f64), String> {
let args: Vec<String> = env::args().collect();
if args.len() != 4 {
return Err(String::from("用法: <num1> <op> <num2>"));
}
let a = args[1].parse::<f64>().map_err(|_| format!("无效的数字: {}", args[1]))?;
let op = args[2].clone();
let b = args[3].parse::<f64>().map_err(|_| format!("无效的数字: {}", args[3]))?;
Ok((a, op, b))
}
fn main() {
match parse_args() {
Ok((a, op, b)) => {
match calculate(a, &op, b) {
Ok(result) => println!("{}", result),
Err(e) => eprintln!("错误: {}", e),
}
}
Err(e) => eprintln!("错误: {}", e),
}
}
练习 12 答案
#[derive(Debug, PartialEq)]
enum MyResult<T, E> {
Ok(T),
Err(E),
}
impl<T, E> MyResult<T, E> {
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> MyResult<U, E> {
match self {
MyResult::Ok(v) => MyResult::Ok(f(v)),
MyResult::Err(e) => MyResult::Err(e),
}
}
fn map_err<F2, F: FnOnce(E) -> F2>(self, f: F) -> MyResult<T, F2> {
match self {
MyResult::Ok(v) => MyResult::Ok(v),
MyResult::Err(e) => MyResult::Err(f(e)),
}
}
fn and_then<U, F: FnOnce(T) -> MyResult<U, E>>(self, f: F) -> MyResult<U, E> {
match self {
MyResult::Ok(v) => f(v),
MyResult::Err(e) => MyResult::Err(e),
}
}
fn unwrap_or(self, default: T) -> T {
match self {
MyResult::Ok(v) => v,
MyResult::Err(_) => default,
}
}
}
fn main() {
let ok: MyResult<i32, &str> = MyResult::Ok(5);
assert_eq!(ok.map(|x| x * 2), MyResult::Ok(10));
let err: MyResult<i32, &str> = MyResult::Err("error");
assert_eq!(err.map(|x| x * 2), MyResult::Err("error"));
println!("所有测试通过!");
}
练习 13 答案
use std::ops::Deref;
struct MyBox<T> {
ptr: *mut T,
}
impl<T> MyBox<T> {
fn new(value: T) -> Self {
let boxed = Box::new(value);
Self { ptr: Box::into_raw(boxed) }
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
println!("Dropping MyBox");
unsafe { let _ = Box::from_raw(self.ptr); }
}
}
fn main() {
let x = MyBox::new(5);
assert_eq!(*x, 5);
let s = MyBox::new(String::from("hello"));
assert_eq!(&*s, "hello");
println!("程序结束");
}
练习 14 答案
use std::sync::{Arc, Mutex, mpsc};
use std::thread;
type Job = Box<dyn FnOnce() + Send + 'static>;
enum Message {
NewJob(Job),
Terminate,
}
struct ThreadPool {
workers: Vec<Worker>,
sender: mpsc::Sender<Message>,
}
struct Worker {
thread: Option<thread::JoinHandle<()>>,
}
impl Worker {
fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Self {
let thread = thread::spawn(move || loop {
let message = receiver.lock().unwrap().recv().unwrap();
match message {
Message::NewJob(job) => job(),
Message::Terminate => break,
}
});
Self { thread: Some(thread) }
}
}
impl ThreadPool {
fn new(size: usize) -> Self {
let (sender, receiver) = mpsc::channel();
let receiver = Arc::new(Mutex::new(receiver));
let workers = (0..size).map(|_| Worker::new(Arc::clone(&receiver))).collect();
Self { workers, sender }
}
fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
self.sender.send(Message::NewJob(Box::new(f))).unwrap();
}
}
impl Drop for ThreadPool {
fn drop(&mut self) {
for _ in &self.workers {
self.sender.send(Message::Terminate).unwrap();
}
for worker in &mut self.workers {
if let Some(thread) = worker.thread.take() {
thread.join().unwrap();
}
}
}
}
fn main() {
let pool = ThreadPool::new(4);
for i in 0..8 {
pool.execute(move || {
println!("任务 {} 执行中", i);
thread::sleep(std::time::Duration::from_millis(100));
});
}
}
练习 15 答案
struct Node<T> {
value: T,
next: Option<Box<Node<T>>>,
}
struct LinkedList<T> {
head: Option<Box<Node<T>>>,
}
struct Iter<'a, T> {
next: Option<&'a Node<T>>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.next.map(|node| {
self.next = node.next.as_deref();
&node.value
})
}
}
impl<T> LinkedList<T> {
fn new() -> Self { Self { head: None } }
fn push(&mut self, value: T) {
self.head = Some(Box::new(Node { value, next: self.head.take() }));
}
fn pop(&mut self) -> Option<T> {
self.head.take().map(|node| {
self.head = node.next;
node.value
})
}
fn len(&self) -> usize {
let mut count = 0;
let mut current = &self.head;
while let Some(node) = current {
count += 1;
current = &node.next;
}
count
}
fn iter(&self) -> Iter<T> {
Iter { next: self.head.as_deref() }
}
}
fn main() {
let mut list = LinkedList::new();
list.push(1);
list.push(2);
list.push(3);
assert_eq!(list.len(), 3);
assert_eq!(list.pop(), Some(3));
for value in list.iter() { println!("{}", value); }
}
练习 16 答案
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &byte) in bytes.iter().enumerate() {
if byte == b' ' {
return &s[..i];
}
}
&s[..]
}
fn main() {
let s = String::from("hello world");
let word = first_word(&s);
assert_eq!(word, "hello");
println!("第一个单词: {}", word);
}
解释:返回的切片 &str 与输入参数 s 具有相同的生命周期。Rust 的生命周期省略规则会自动推断。
练习 17 答案
struct TextAnalyzer<'a> {
text: &'a str,
}
impl<'a> TextAnalyzer<'a> {
fn new(text: &'a str) -> Self { Self { text } }
fn word_count(&self) -> usize {
self.text.split_whitespace().count()
}
fn longest_word(&self) -> Option<&'a str> {
self.text.split_whitespace().max_by_key(|w| w.len())
}
fn contains(&self, word: &str) -> bool {
self.text.split_whitespace().any(|w| w == word)
}
}
fn main() {
let text = "the quick brown fox jumps over the lazy dog";
let analyzer = TextAnalyzer::new(text);
assert_eq!(analyzer.word_count(), 9);
assert_eq!(analyzer.longest_word(), Some("jumps"));
}
练习 18 答案
fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s1.len() >= s2.len() { s1 } else { s2 }
}
fn combine_and_process<'a, 'b>(s1: &'a str, s2: &'b str) -> String {
format!("{} - {}", s1, s2)
}
fn main() {
let s1 = String::from("hello");
let s2 = String::from("world!");
assert_eq!(longer(&s1, &s2), "world!");
let s1 = String::from("long string");
let result;
{
let s2 = String::from("short");
result = longer(&s1, &s2);
}
println!("较长的是: {}", result);
}
练习 19 答案
use std::f64::consts::PI;
trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
fn name(&self) -> &str;
}
struct Circle { radius: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { PI * self.radius * self.radius }
fn perimeter(&self) -> f64 { 2.0 * PI * self.radius }
fn name(&self) -> &str { "圆形" }
}
struct Rectangle { width: f64, height: f64 }
impl Shape for Rectangle {
fn area(&self) -> f64 { self.width * self.height }
fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) }
fn name(&self) -> &str { "矩形" }
}
fn total_area(shapes: &[Box<dyn Shape>]) -> f64 {
shapes.iter().map(|s| s.area()).sum()
}
fn main() {
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 1.0 }),
Box::new(Rectangle { width: 2.0, height: 3.0 }),
];
println!("总面积: {:.2}", total_area(&shapes));
}
练习 20 答案
trait Container {
type Item;
fn new() -> Self;
fn insert(&mut self, item: Self::Item);
fn remove(&mut self) -> Option<Self::Item>;
fn len(&self) -> usize;
}
struct VecContainer<T> { data: Vec<T> }
impl<T> Container for VecContainer<T> {
type Item = T;
fn new() -> Self { Self { data: Vec::new() } }
fn insert(&mut self, item: Self::Item) { self.data.push(item); }
fn remove(&mut self) -> Option<Self::Item> { self.data.pop() }
fn len(&self) -> usize { self.data.len() }
}
fn test_container<C: Container<Item=i32>>() {
let mut c = C::new();
assert_eq!(c.len(), 0);
c.insert(1);
c.insert(2);
assert_eq!(c.remove(), Some(2));
}
fn main() {
test_container::<VecContainer<i32>>();
println!("所有测试通过!");
}
练习 21-45 答案
由于篇幅限制,练习 21-45 的完整答案请参考原文件或在线资源。以下是关键练习的简要答案框架:
练习 21(From/Into)
impl From<Fahrenheit> for Celsius {
fn from(f: Fahrenheit) -> Self { Celsius((f.0 - 32.0) * 5.0 / 9.0) }
}
练习 22(操作符重载)
impl Add for Complex {
type Output = Complex;
fn add(self, other: Complex) -> Complex {
Complex::new(self.real + other.real, self.imag + other.imag)
}
}
练习 23(宏基础)
macro_rules! my_vec {
($($x:expr),*) => {{
let mut v = Vec::new();
$(v.push($x);)*
v
}};
}
练习 39(Send/Sync)
Rc<T>不是SendArc<T>是Send + Sync(当T: Send + Sync)- 使用
PhantomData<*const ()>标记!Send
练习 40(原子操作)
struct AtomicCounter { value: AtomicI64 }
impl AtomicCounter {
fn fetch_add(&self, delta: i64) -> i64 {
self.value.fetch_add(delta, Ordering::SeqCst)
}
}
练习 41(Pin)
struct SelfReferential {
data: String,
pointer: *const String,
_marker: PhantomPinned,
}
知识点索引
| 知识点 | 练习编号 |
|---|---|
| 基础语法 | 1, 2, 3 |
| 所有权与借用 | 4, 15 |
| 结构体与方法 | 5, 28 |
| 枚举与模式匹配 | 6, 7 |
| 泛型 | 8, 20 |
| Trait | 8, 19, 20, 21, 22 |
| 生命周期 | 16, 17, 18 |
| 闭包与迭代器 | 9, 32 |
| 智能指针 | 13, 27, 41 |
| 错误处理 | 11, 12 |
| 并发基础 | 14, 25, 26 |
| 并发进阶 | 40 |
| 异步编程 | 31 |
| 宏 | 23, 24, 42, 43 |
| 模块系统 | 36 |
| 测试 | 37 |
| 条件编译 | 38 |
| 类型安全 | 29, 30 |
| FFI | 44 |
| 综合项目 | 10, 35, 45 |
浙公网安备 33010602011771号