generic types, traits and lifetimes

- get claude to create rustlings style exercises based on chapter 10 of the book
- update CLAUDE.md to prevent it from producing incorrect exercises
- complete exercises/01-generic-cache-system
This commit is contained in:
2026-01-22 11:58:33 +00:00
parent f55039411e
commit 02fbf819e4
14 changed files with 567 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
[package]
name = "generic_methods"
version = "0.1.0"
edition = "2024"
[dependencies]

View File

@@ -0,0 +1,15 @@
# Generic Methods & Implementations
Build a generic data transformer that can convert, filter, and manipulate collections of any type. You'll practice writing methods on generic structs and using multiple type parameters in implementation blocks.
## What you'll practice
- Writing methods for generic structs with `impl<T>` blocks
- Using multiple type parameters in methods like `<T, U>`
- Associated functions vs instance methods on generic types
- Method chaining with generic return types
## Further information
- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
- [Generic Data Types](https://doc.rust-lang.org/book/ch10-01-syntax.html)

View File

@@ -0,0 +1,122 @@
// TODO: Make this struct generic over type T
// It should store a collection of items and provide transformation methods
struct DataTransformer {
items: Vec<i32>,
}
// TODO: Implement methods for DataTransformer<T>
impl DataTransformer<i32> {
// TODO: Associated function to create new transformer with empty collection
fn new() -> Self {
todo!("Create new DataTransformer")
}
// TODO: Associated function to create transformer from existing vector
fn from_vec(items: Vec<i32>) -> Self {
todo!("Create DataTransformer from vector")
}
// TODO: Method to add an item to the collection
fn add(&mut self, item: i32) {
todo!("Add item to collection")
}
// TODO: Method to get length of collection
fn len(&self) -> usize {
todo!("Return length")
}
// TODO: Method to transform each item using a closure and return new DataTransformer
// This should work: transformer.map(|x| x * 2)
fn map<U, F>(&self, f: F) -> DataTransformer<U>
where
F: Fn(&i32) -> U,
{
todo!("Transform each item")
}
// TODO: Method to filter items using a predicate and return new DataTransformer with same type
fn filter<F>(&self, predicate: F) -> DataTransformer<i32>
where
F: Fn(&i32) -> bool,
{
todo!("Filter items")
}
// TODO: Method to find first item matching predicate
fn find<F>(&self, predicate: F) -> Option<&i32>
where
F: Fn(&i32) -> bool,
{
todo!("Find first matching item")
}
// TODO: Method to collect all items into a vector
fn collect(self) -> Vec<i32> {
todo!("Collect into vector")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_creation_and_basic_ops() {
let mut transformer: DataTransformer<i32> = DataTransformer::new();
assert_eq!(transformer.len(), 0);
transformer.add(10);
transformer.add(20);
assert_eq!(transformer.len(), 2);
let from_vec: DataTransformer<String> = DataTransformer::from_vec(vec!["hello".to_string(), "world".to_string()]);
assert_eq!(from_vec.len(), 2);
}
#[test]
fn test_map_transformation() {
let transformer = DataTransformer::from_vec(vec![1, 2, 3, 4]);
let doubled: DataTransformer<i32> = transformer.map(|x| x * 2);
assert_eq!(doubled.collect(), vec![2, 4, 6, 8]);
let strings: DataTransformer<String> = transformer.map(|x| x.to_string());
assert_eq!(strings.collect(), vec!["1", "2", "3", "4"]);
}
#[test]
fn test_filter() {
let transformer = DataTransformer::from_vec(vec![1, 2, 3, 4, 5, 6]);
let evens = transformer.filter(|x| *x % 2 == 0);
assert_eq!(evens.collect(), vec![2, 4, 6]);
}
#[test]
fn test_find() {
let transformer = DataTransformer::from_vec(vec![10, 20, 30, 40]);
assert_eq!(transformer.find(|x| *x > 25), Some(&30));
assert_eq!(transformer.find(|x| *x > 50), None);
}
#[test]
fn test_method_chaining() {
let result = DataTransformer::from_vec(vec![1, 2, 3, 4, 5, 6])
.filter(|x| *x % 2 == 0) // Keep evens: [2, 4, 6]
.map(|x| x * 10) // Multiply by 10: [20, 40, 60]
.collect();
assert_eq!(result, vec![20, 40, 60]);
}
#[test]
fn test_different_types() {
let string_transformer = DataTransformer::from_vec(vec!["rust".to_string(), "is".to_string(), "awesome".to_string()]);
let lengths: DataTransformer<usize> = string_transformer.map(|s| s.len());
assert_eq!(lengths.collect(), vec![4, 2, 7]);
let long_words = DataTransformer::from_vec(vec!["a".to_string(), "hello".to_string(), "world".to_string()])
.filter(|s| s.len() > 3);
assert_eq!(long_words.collect(), vec!["hello".to_string(), "world".to_string()]);
}
}