9.9 Generic Structs
Structs can be generic, allowing them to work with different concrete types.
// Generic struct `Point<T>` struct Point<T> { x: T, y: T, } // Generic struct with multiple type parameters struct Pair<T, U> { first: T, second: U, } fn main() { // Instantiate with inferred types let integer_point = Point { x: 5, y: 10 }; // Point<i32> let float_point = Point { x: 1.0, y: 4.0 }; // Point<f64> let pair = Pair { first: "hello", second: 123 }; // Pair<&str, i32> println!("Int Point: x={}, y={}", integer_point.x, integer_point.y); println!("Float Point: x={}, y={}", float_point.x, float_point.y); println!("Pair: first={}, second={}", pair.first, pair.second); }
9.9.1 Methods on Generic Structs
Methods can be defined on generic structs using impl<T>
.
struct Point<T> { x: T, y: T } impl<T> Point<T> { // This method works for any T fn x(&self) -> &T { &self.x } } fn main() { let p = Point { x: 5, y: 10 }; println!("x coordinate: {}", p.x()); }
9.9.2 Constraining Generic Types with Trait Bounds
Trait bounds restrict generic types to those implementing specific traits, enabling methods that require certain capabilities.
use std::fmt::Display; // For printing use std::ops::Add; // For addition struct Container<T> { value: T, } impl<T> Container<T> { fn new(value: T) -> Self { Container { value } } } // Method only available if T implements Display impl<T: Display> Container<T> { fn print(&self) { println!("Container holds: {}", self.value); } } // Method only available if T implements Add<Output=T> + Copy // (Requires T can be added to itself and is copyable) impl<T: Add<Output = T> + Copy> Container<T> { fn add_to_self(&self) -> T { self.value + self.value // Requires Add and Copy } } fn main() { let c_int = Container::new(10); c_int.print(); // Works (i32 implements Display) println!("Doubled: {}", c_int.add_to_self()); // Works (i32 implements Add + Copy) let c_str = Container::new("hello"); c_str.print(); // Works (&str implements Display) // println!("Doubled: {}", c_str.add_to_self()); Error! &str doesn't impl Add, Copy }
Trait bounds are central to Rust’s polymorphism and type safety with generics.