Generic Data Types
In this chapter, we'll explore write functions and structs that work with any type.
Generic Data Types
We use generics to create definitions for items like functions and structs, which we can then use with many different concrete types.
Generic Functions
Define a generic function with generic<T>:
module main
generic<T> where T: Ord
fn largest(list: Vec<T>) -> T {
let mut largest = list[0]
for item in list {
if item > largest {
largest = item
}
}
return largest
}
fn main() -> void {
let numbers = [34, 50, 25, 100, 65]
let result = largest(numbers)
println("Largest number is ", result)
let chars = ['y', 'm', 'a', 'q']
let result = largest(chars)
println("Largest char is ", result)
}The where T: Ord constraint ensures T can be compared.
Generic Structs
module main
generic<T>
struct Point {
x: T,
y: T,
}
fn main() -> void {
let integer = Point { x: 5, y: 10 }
let float = Point { x: 1.0, y: 4.0 }
}Multiple type parameters:
module main
generic<T, U>
struct Point {
x: T,
y: U,
}
fn main() -> void {
let both_int = Point { x: 5, y: 10 }
let both_float = Point { x: 1.0, y: 4.0 }
let int_and_float = Point { x: 5, y: 4.0 }
}Generic Enums
generic<T>
enum Option {
Some(T),
None,
}
generic<T, E>
enum Result {
Ok(T),
Err(E),
}Generic Methods
module main
generic<T>
struct Point {
x: T,
y: T,
}
generic<T>
impl Point<T> {
fn x(self) -> T {
return self.x
}
}
fn main() -> void {
let p = Point { x: 5, y: 10 }
println("p.x = ", p.x())
}Methods with different generic parameters:
generic<X1, Y1>
struct Point {
x: X1,
y: Y1,
}
generic<X1, Y1>
impl Point<X1, Y1> {
generic<X2, Y2>
fn mixup(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
return Point {
x: self.x,
y: other.y,
}
}
}Performance
Mana compiles generic code using monomorphization—generating concrete code for each type used. There's no runtime cost to generics.
Continue to Traits: Defining Shared Behavior.