You've already forked rust-tutor
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:
6
exercises/04-generic-methods/Cargo.toml
Normal file
6
exercises/04-generic-methods/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "generic_methods"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
15
exercises/04-generic-methods/README.md
Normal file
15
exercises/04-generic-methods/README.md
Normal 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)
|
||||
122
exercises/04-generic-methods/src/main.rs
Normal file
122
exercises/04-generic-methods/src/main.rs
Normal 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()]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user