2023-11-29 10:39:24 -05:00
|
|
|
---
|
|
|
|
minutes: 5
|
|
|
|
---
|
|
|
|
|
|
|
|
# Generic Functions
|
|
|
|
|
|
|
|
Rust supports generics, which lets you abstract algorithms or data structures
|
2023-12-31 00:15:07 +01:00
|
|
|
(such as sorting or a binary tree) over the types used or stored.
|
2023-11-29 10:39:24 -05:00
|
|
|
|
|
|
|
```rust,editable
|
2025-03-03 07:03:10 -08:00
|
|
|
fn pick<T>(cond: bool, left: T, right: T) -> T {
|
|
|
|
if cond {
|
|
|
|
left
|
2023-11-29 10:39:24 -05:00
|
|
|
} else {
|
2025-03-03 07:03:10 -08:00
|
|
|
right
|
2023-11-29 10:39:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2025-03-03 07:03:10 -08:00
|
|
|
println!("picked a number: {:?}", pick(true, 222, 333));
|
|
|
|
println!("picked a string: {:?}", pick(false, 'L', 'R'));
|
2023-11-29 10:39:24 -05:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
2025-03-03 07:03:10 -08:00
|
|
|
- It can be helpful to show the monomorphized versions of `pick`, either before
|
|
|
|
talking about the generic `pick` in order to show how generics can reduce code
|
|
|
|
duplication, or after talking about generics to show how monomorphization
|
|
|
|
works.
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn pick_i32(cond: bool, left: i32, right: i32) -> i32 {
|
|
|
|
if cond {
|
|
|
|
left
|
|
|
|
} else {
|
|
|
|
right
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pick_char(cond: bool, left: char, right: char) -> char {
|
|
|
|
if cond {
|
|
|
|
left
|
|
|
|
} else {
|
|
|
|
right
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-12-31 00:15:07 +01:00
|
|
|
- Rust infers a type for T based on the types of the arguments and return value.
|
2023-11-29 10:39:24 -05:00
|
|
|
|
2025-03-03 07:03:10 -08:00
|
|
|
- In this example we only use the primitive types `i32` and `char` for `T`, but
|
2024-09-20 14:19:53 -07:00
|
|
|
we can use any type here, including user-defined types:
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
struct Foo {
|
|
|
|
val: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
pick(123, Foo { val: 7 }, Foo { val: 456 });
|
|
|
|
```
|
|
|
|
|
2023-12-31 00:15:07 +01:00
|
|
|
- This is similar to C++ templates, but Rust partially compiles the generic
|
2023-11-29 10:39:24 -05:00
|
|
|
function immediately, so that function must be valid for all types matching
|
|
|
|
the constraints. For example, try modifying `pick` to return `even + odd` if
|
|
|
|
`n == 0`. Even if only the `pick` instantiation with integers is used, Rust
|
|
|
|
still considers it invalid. C++ would let you do this.
|
|
|
|
|
2023-12-31 00:15:07 +01:00
|
|
|
- Generic code is turned into non-generic code based on the call sites. This is
|
|
|
|
a zero-cost abstraction: you get exactly the same result as if you had
|
2023-11-29 10:39:24 -05:00
|
|
|
hand-coded the data structures without the abstraction.
|
|
|
|
|
|
|
|
</details>
|