# Generic Types, Traits, and Lifetimes # Generics A tools for effectively handling the duplication of concepts. One of these tools is *generics* They are abstract stand-ins for concrete types or other properties We can express the behavior of generics or how they relate to other generics without knowing what type that will be in place when compiling and running the code. Functions can either take parameters of some generic type or a concrete type (like a `i32` or `String`) in the same way they take parameters with unknown values to run the same code on multiple concrete values One example where concrete values were already used was with `Option`, `Vec`, `HashMap` and `Result` This chapter covers 3 things 1. [Reducing Code duplication](Reducing_Code_Duplication.md) 1. [Generics](Generics.md) 1. [Traits](Traits.md) 2. [Lifetimes](Lifetimes.md) ## Generic Type Parameters, Trait Bounds, and Lifetimes Together Here is an example with all of them together ```rust use std::fmt::Display; fn longest_with_an_announcement<'a, T>( x: &'a str, y: &'a str, ann: T, ) -> &'a str where T: Display, { println!("Announcement! {ann}"); if x.len() > y.len() { x } else { y } } ``` This is the `longest` function that returns the longer of the two string slices. Now it has a parameter called `ann` of the generic type `T` which can only be any type that implements the `Display` trait as specified by the `where` clause The `ann` parameter will be printed using `{}`, which is why the `Display` trait is necessary Because lifetimes are a type of generic the declarations of the lifetime parameter `'a` and the generic type parameter `T` go in the same list inside the angle brackets after the function name