Generics
Generics let you write functions and structs that work with any type.
Generic functions
Add type parameters in angle brackets after the function name:
fn identity<T>(x:T -- y:T) {
-> val
val
}
fn main() {
42 identity print nl // 42
3.14 identity print nl // 3.14
"hello" identity print nl // hello
}
The compiler infers the type T from the argument at each call site. No explicit type annotation is needed when calling.
Multiple type parameters
Functions can have more than one type parameter:
fn pair<A, B>(a:A b:B -- a:A b:B) {
-> second -> first
first second
}
fn main() {
1 "one" pair
print nl // one
print nl // 1
}
Generic structs
Structs can also be generic:
struct Box<T> {
value:T
}
fn main() {
Box<i64> { value = 42 } -> b
b @value print nl // 42
}
!!! note Generic structs currently work best with integer types. For structs with mixed types, prefer non-generic structs with explicit field types.
Built-in generic operations
make
Create typed arrays:
10 make<i64> -> ints // Array of 10 integers
5 make<f64> -> floats // Array of 5 floats
3 make<str> -> strings // Array of 3 strings
See Arrays for more on array operations.
cast
Convert between types:
fn main() {
3.14 cast<i64> print nl // 3 (truncates)
42 cast<f64> print nl // 42
100 cast<str> print nl // 100
"42" cast<i64> print nl // 42
"2.5" cast<f64> print nl // 2.5
}
| From | To | Behavior |
|---|---|---|
f64 |
i64 |
Truncates decimal |
i64 |
f64 |
Exact conversion |
i64 |
str |
Decimal string |
f64 |
str |
Decimal string |
str |
i64 |
Parses integer |
str |
f64 |
Parses float |
How it works
The compiler uses monomorphization: it generates a specialized version of each generic function for every type combination used. This means generic code has the same performance as hand-written specialized functions.
What's next?
Learn about Memory Management for manual memory control.