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,112 @@
use std::collections::HashMap;
use std::hash::Hash;
fn cache_get<K: Eq + Hash, V>(map: &HashMap<K, V>, key: K) -> Option<&V> {
for (k, v) in map.iter() {
if *k == key {
return Some(&v);
}
}
return None;
}
fn cache_insert<K: Eq + Hash, V: Copy>(cache: &mut HashMap<K, V>, key: K, value: V) -> Option<V> {
for (k, v) in cache.iter() {
let return_value = *v;
if *k == key {
//update value
cache.insert(key, value);
}
//"there was an existing record with this key which we wrote over"
//"and the key we wrote over was return_value"
return Some(return_value);
}
// insert new value
cache.insert(key, value);
// "there wasnt an existing record with this key"
return None;
}
fn cache_compute_if_absent<K: Eq + Hash, V, F>(cache: &mut HashMap<K, V>, key: K, compute: F) -> &V
where
F: Fn() -> V,
{
cache.entry(key).or_insert_with(compute)
}
fn batch_lookup<'a, K: Eq + Hash, V>(cache: &'a HashMap<K, V>, keys: &[K]) -> Vec<&'a V> {
let mut result = Vec::new();
for key in keys {
if let Some(value) = cache.get(key) {
result.push(value);
}
}
return result;
}
fn main() {
println!("let's go!");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cache_get_found() {
let mut cache = HashMap::new();
cache.insert("key1", 42);
assert_eq!(cache_get(&cache, &"key1"), Some(&42));
}
#[test]
fn test_cache_get_missing() {
let cache: HashMap<&str, i32> = HashMap::new();
assert_eq!(cache_get(&cache, &"missing"), None);
}
#[test]
fn test_cache_insert_new() {
let mut cache = HashMap::new();
assert_eq!(cache_insert(&mut cache, "new", 100), None);
assert_eq!(cache.get("new"), Some(&100));
}
#[test]
fn test_cache_insert_existing() {
let mut cache = HashMap::new();
cache.insert("key", 50);
assert_eq!(cache_insert(&mut cache, "key", 75), Some(50));
assert_eq!(cache.get("key"), Some(&75));
}
#[test]
fn test_compute_if_absent_missing() {
let mut cache = HashMap::new();
let result = cache_compute_if_absent(&mut cache, "compute", || "computed".to_string());
assert_eq!(result, &"computed".to_string());
assert_eq!(cache.get("compute"), Some(&"computed".to_string()));
}
#[test]
fn test_compute_if_absent_exists() {
let mut cache = HashMap::new();
cache.insert("existing", "original".to_string());
let result =
cache_compute_if_absent(&mut cache, "existing", || "should not run".to_string());
assert_eq!(result, &"original".to_string());
}
#[test]
fn test_batch_lookup() {
let mut cache = HashMap::new();
cache.insert(1, "one");
cache.insert(3, "three");
cache.insert(5, "five");
let keys = [1, 2, 3, 4, 5];
let results = batch_lookup(&cache, &keys);
assert_eq!(results, vec![&"one", &"three", &"five"]);
}
}