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.