mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-28 06:49:19 +00:00
git commit -m "feat: Add exercises for new Rust features
Add exercises for: - const generics - let-else statements - generic associated types (GAT) - async traits These exercises help learners understand and practice new Rust features introduced in recent versions."
This commit is contained in:
parent
e36dd7a120
commit
9db703b468
@ -54,6 +54,7 @@ rustlings-macros = { path = "rustlings-macros", version = "=6.4.0" }
|
||||
serde_json = "1.0"
|
||||
serde.workspace = true
|
||||
toml_edit.workspace = true
|
||||
tokio = { version = "1.36", features = ["full"] }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
rustix = { version = "1.0", default-features = false, features = ["std", "stdio", "termios"] }
|
||||
|
||||
67
exercises/24_new_features/01_const_generics.rs
Normal file
67
exercises/24_new_features/01_const_generics.rs
Normal file
@ -0,0 +1,67 @@
|
||||
// const_generics.rs
|
||||
//
|
||||
// Const 泛型允许我们使用编译时常量作为泛型参数。这在处理固定大小的数组和其他
|
||||
// 需要编译时常量的场景特别有用。
|
||||
//
|
||||
// 在这个练习中,我们将实现一个简单的固定大小数组包装器,它可以安全地访问数组元素
|
||||
// 并提供一些实用的方法。
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// TODO: 实现一个泛型结构体 FixedArray<T, const N: usize>
|
||||
// 它应该包装一个固定大小的数组 [T; N]
|
||||
struct FixedArray<T, const N: usize> {
|
||||
data: [T; N],
|
||||
}
|
||||
|
||||
impl<T, const N: usize> FixedArray<T, N> {
|
||||
// TODO: 实现 new 方法,它接受一个数组并返回 FixedArray
|
||||
fn new(arr: [T; N]) -> Self {
|
||||
todo!("创建一个新的 FixedArray 实例")
|
||||
}
|
||||
|
||||
// TODO: 实现 get 方法,它安全地返回索引处的元素引用
|
||||
fn get(&self, index: usize) -> Option<&T> {
|
||||
todo!("返回指定索引处的元素,如果索引越界则返回 None")
|
||||
}
|
||||
|
||||
// TODO: 实现 len 方法,返回数组的长度
|
||||
fn len(&self) -> usize {
|
||||
todo!("返回数组的长度")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fixed_array() {
|
||||
let arr = FixedArray::new([1, 2, 3, 4, 5]);
|
||||
|
||||
// 测试长度
|
||||
assert_eq!(arr.len(), 5);
|
||||
|
||||
// 测试有效索引
|
||||
assert_eq!(arr.get(0), Some(&1));
|
||||
assert_eq!(arr.get(4), Some(&5));
|
||||
|
||||
// 测试无效索引
|
||||
assert_eq!(arr.get(5), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_types() {
|
||||
let arr = FixedArray::new(["hello", "world"]);
|
||||
assert_eq!(arr.len(), 2);
|
||||
assert_eq!(arr.get(0), Some(&"hello"));
|
||||
assert_eq!(arr.get(1), Some(&"world"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_array() {
|
||||
let arr: FixedArray<i32, 0> = FixedArray::new([]);
|
||||
assert_eq!(arr.len(), 0);
|
||||
assert_eq!(arr.get(0), None);
|
||||
}
|
||||
}
|
||||
77
exercises/24_new_features/02_let_else.rs
Normal file
77
exercises/24_new_features/02_let_else.rs
Normal file
@ -0,0 +1,77 @@
|
||||
// let_else.rs
|
||||
//
|
||||
// let-else 语句是 Rust 1.65 中引入的新特性。它允许我们在模式匹配失败时
|
||||
// 提前返回或中断执行。这个特性特别适合于处理 Option 和 Result 类型。
|
||||
//
|
||||
// 在这个练习中,我们将使用 let-else 语句来简化错误处理代码。
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Rectangle {
|
||||
top_left: Point,
|
||||
bottom_right: Point,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
// TODO: 使用 let-else 语句实现这个函数
|
||||
// 如果参数无效(左上角点的坐标大于右下角点的坐标),返回 None
|
||||
fn new(top_left: Point, bottom_right: Point) -> Option<Rectangle> {
|
||||
todo!("实现 Rectangle::new,使用 let-else 语句验证参数")
|
||||
}
|
||||
|
||||
// TODO: 使用 let-else 语句实现这个函数
|
||||
// 函数应该解析字符串格式的矩形定义,格式为 "x1,y1,x2,y2"
|
||||
// 其中 x1,y1 是左上角坐标,x2,y2 是右下角坐标
|
||||
fn parse(s: &str) -> Option<Rectangle> {
|
||||
todo!("实现字符串解析为 Rectangle 的功能")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_valid_rectangle() {
|
||||
let rect = Rectangle::new(
|
||||
Point { x: 0, y: 0 },
|
||||
Point { x: 10, y: 10 }
|
||||
);
|
||||
assert!(rect.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_rectangle() {
|
||||
let rect = Rectangle::new(
|
||||
Point { x: 10, y: 10 },
|
||||
Point { x: 0, y: 0 }
|
||||
);
|
||||
assert!(rect.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_valid() {
|
||||
let rect = Rectangle::parse("0,0,10,10");
|
||||
assert_eq!(rect, Some(Rectangle {
|
||||
top_left: Point { x: 0, y: 0 },
|
||||
bottom_right: Point { x: 10, y: 10 }
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_invalid_format() {
|
||||
assert!(Rectangle::parse("invalid").is_none());
|
||||
assert!(Rectangle::parse("0,0,10").is_none());
|
||||
assert!(Rectangle::parse("0,0,10,10,12").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_invalid_coordinates() {
|
||||
assert!(Rectangle::parse("10,10,0,0").is_none());
|
||||
}
|
||||
}
|
||||
77
exercises/24_new_features/03_gat.rs
Normal file
77
exercises/24_new_features/03_gat.rs
Normal file
@ -0,0 +1,77 @@
|
||||
// gat.rs
|
||||
//
|
||||
// GAT (Generic Associated Types) 是 Rust 1.65 中引入的一个强大特性。
|
||||
// 它允许在关联类型中使用泛型参数,这在创建容器类型和迭代器时特别有用。
|
||||
//
|
||||
// 在这个练习中,我们将实现一个简单的 Map 容器,它可以存储不同类型的值
|
||||
// 并提供类型安全的访问方法。
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// 定义一个特征,表示可以存储和检索值的容器
|
||||
trait Container {
|
||||
// TODO: 使用 GAT 定义一个关联类型 Value,它有一个生命周期参数
|
||||
type Value<'a>: 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
// 获取容器中的值的引用
|
||||
fn get<'a>(&'a self) -> Self::Value<'a>;
|
||||
}
|
||||
|
||||
// 一个简单的包装类型
|
||||
struct Wrapper<T>(T);
|
||||
|
||||
// TODO: 为 Wrapper<T> 实现 Container 特征
|
||||
// Value 类型应该是对 T 的引用
|
||||
impl<T> Container for Wrapper<T> {
|
||||
type Value<'a> = todo!("定义正确的关联类型");
|
||||
|
||||
fn get<'a>(&'a self) -> Self::Value<'a> {
|
||||
todo!("返回对内部值的引用")
|
||||
}
|
||||
}
|
||||
|
||||
// 一个选项包装类型
|
||||
struct OptionWrapper<T>(Option<T>);
|
||||
|
||||
// TODO: 为 OptionWrapper<T> 实现 Container 特征
|
||||
// Value 类型应该是 Option<&T>
|
||||
impl<T> Container for OptionWrapper<T> {
|
||||
type Value<'a> = todo!("定义正确的关联类型");
|
||||
|
||||
fn get<'a>(&'a self) -> Self::Value<'a> {
|
||||
todo!("返回 Option<&T>")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_wrapper() {
|
||||
let w = Wrapper(42);
|
||||
assert_eq!(*w.get(), 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option_wrapper_some() {
|
||||
let w = OptionWrapper(Some(42));
|
||||
assert_eq!(w.get(), Some(&42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option_wrapper_none() {
|
||||
let w: OptionWrapper<i32> = OptionWrapper(None);
|
||||
assert_eq!(w.get(), None);
|
||||
}
|
||||
|
||||
// 这个测试确保我们的实现可以处理不同的生命周期
|
||||
#[test]
|
||||
fn test_lifetime() {
|
||||
let w = Wrapper(String::from("hello"));
|
||||
let r: &String = w.get();
|
||||
assert_eq!(r, "hello");
|
||||
}
|
||||
}
|
||||
103
exercises/24_new_features/04_async_trait.rs
Normal file
103
exercises/24_new_features/04_async_trait.rs
Normal file
@ -0,0 +1,103 @@
|
||||
// async_trait.rs
|
||||
//
|
||||
// 异步特征是 Rust 1.75 中稳定的新特性。它允许在特征中直接定义异步方法,
|
||||
// 不再需要使用 async-trait 宏。这个特性大大简化了异步编程的代码。
|
||||
//
|
||||
// 在这个练习中,我们将实现一个简单的异步数据获取接口。
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
// 模拟一个数据源
|
||||
struct DataSource {
|
||||
data: Vec<String>,
|
||||
}
|
||||
|
||||
impl DataSource {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
data: vec![
|
||||
"Hello".to_string(),
|
||||
"World".to_string(),
|
||||
"Rust".to_string(),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 实现一个异步特征 AsyncDataFetcher
|
||||
// 它应该包含以下异步方法:
|
||||
// - fetch_data: 获取指定索引的数据
|
||||
// - fetch_all: 获取所有数据
|
||||
// - count: 获取数据总数
|
||||
trait AsyncDataFetcher {
|
||||
async fn fetch_data(&self, index: usize) -> Option<String>;
|
||||
async fn fetch_all(&self) -> Vec<String>;
|
||||
async fn count(&self) -> usize;
|
||||
}
|
||||
|
||||
// TODO: 为 DataSource 实现 AsyncDataFetcher 特征
|
||||
impl AsyncDataFetcher for DataSource {
|
||||
async fn fetch_data(&self, index: usize) -> Option<String> {
|
||||
todo!("模拟异步获取数据,使用 tokio::time::sleep 增加延迟")
|
||||
}
|
||||
|
||||
async fn fetch_all(&self) -> Vec<String> {
|
||||
todo!("模拟异步获取所有数据")
|
||||
}
|
||||
|
||||
async fn count(&self) -> usize {
|
||||
todo!("模拟异步获取数据数量")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tokio::time::sleep;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fetch_data() {
|
||||
let source = DataSource::new();
|
||||
|
||||
// 测试获取有效索引的数据
|
||||
assert_eq!(source.fetch_data(0).await, Some("Hello".to_string()));
|
||||
assert_eq!(source.fetch_data(1).await, Some("World".to_string()));
|
||||
|
||||
// 测试获取无效索引的数据
|
||||
assert_eq!(source.fetch_data(10).await, None);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fetch_all() {
|
||||
let source = DataSource::new();
|
||||
let all_data = source.fetch_all().await;
|
||||
|
||||
assert_eq!(all_data, vec![
|
||||
"Hello".to_string(),
|
||||
"World".to_string(),
|
||||
"Rust".to_string(),
|
||||
]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_count() {
|
||||
let source = DataSource::new();
|
||||
assert_eq!(source.count().await, 3);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_concurrent_fetch() {
|
||||
let source = DataSource::new();
|
||||
|
||||
// 测试并发获取数据
|
||||
let (data1, data2) = tokio::join!(
|
||||
source.fetch_data(0),
|
||||
source.fetch_data(1)
|
||||
);
|
||||
|
||||
assert_eq!(data1, Some("Hello".to_string()));
|
||||
assert_eq!(data2, Some("World".to_string()));
|
||||
}
|
||||
}
|
||||
16
exercises/24_new_features/README.md
Normal file
16
exercises/24_new_features/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Rust 新特性练习
|
||||
|
||||
这个章节包含了一些 Rust 最新特性的练习。通过这些练习,你将学习到:
|
||||
|
||||
1. const 泛型(Rust 1.51+)
|
||||
2. GAT (Generic Associated Types) (Rust 1.65+)
|
||||
3. let-else 语句(Rust 1.65+)
|
||||
4. 异步特征(Rust 1.75+)
|
||||
|
||||
## 推荐阅读
|
||||
|
||||
* [Rust 1.51 发布说明](https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html)
|
||||
* [Rust 1.65 发布说明](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html)
|
||||
* [Rust 1.75 发布说明](https://blog.rust-lang.org/2023/12/28/Rust-1.75.0.html)
|
||||
* [Rust Reference: Generic Associated Types](https://doc.rust-lang.org/reference/items/associated-items.html#generic-associated-types-gats)
|
||||
* [Rust Reference: const 泛型](https://doc.rust-lang.org/reference/items/generics.html#const-generics)
|
||||
Loading…
x
Reference in New Issue
Block a user