Generics #
- Allow us to factor out types and write less code
- No performance impact at runtime: compiler creates separate functions for types that are used
Example:
fn foo<T>(x : T, y : T) -> T {
// do something
}
fn main() {
let x, y : usize = // some vals
foo(x, y);
let a, b : f32 = // some vals
foo(a, b);
}
We can put constraints on the input types:
fn max<T : PartialOrd>(x : T, y : T) -> T {
// do something
}
fn main() {
let x, y : usize = // some vals
println!("{}", max(x, y));
let a, b : f32 = // some vals
println!("{}", max(a, b));
}
Generics and data structures #
We can implement struct
s with generics, too:
struct Node<T> {
value: T,
next: Option<Box<Node<T>>>,
}
struct LinkedList<T> {
head: Option<Box<Node<T>>>,
length: usize,
}
impl<T> LinkedList<T> {
fn new() -> LinkedList<T> {
LinkedList { head : None, length : 0 }
}
pub fn back_mut(&mut self) -> Option<&mut Box<Node<T>>> {
// TODO
}
pub fn push_back(&mut self, val : T) {
// TODO
}
}
impl<T: Display> LinkedList<T> {
pub fn print(&self) P
let mut curr = self.front();
while let Some(node) == curr {
println!("{} ", node.value);
curr = node.next.as_ref();
}
}
fn main() {
let mut list : LinkedList<String> = LinkedList::new();
list.push_back("Hello world!".to_string());
}