Generic Functions

Rust supports generics, which lets you abstract algorithms or data structures (such as sorting or a binary tree) over the types used or stored.

1. ```
   /// Pick `even` or `odd` depending on the value of `n`.
   ```
2. ```
   fn pick<T>(n: i32, even: T, odd: T) -> T {
   ```
3. ```
       if n % 2 == 0 {
   ```
4. ```
           even
   ```
5. ```
       } else {
   ```
6. ```
           odd
   ```
7. ```
       }
   ```
8. ```
   }
   ```

10. ```
    fn main() {
    ```
11. ```
        println!("picked a number: {:?}", pick(97, 222, 333));
    ```
12. ```
        println!("picked a string: {:?}", pick(28, "dog", "cat"));
    ```
13. ```
    }
    ```

This slide should take about 5 minutes.

  • Rust infers a type for T based on the types of the arguments and return value.
  • In this example we only use the primitive types i32 and &str for T, but we can use any type here, including user-defined types:

``` 1. struct Foo { 2. val: u8, 3. }

  1. pick(123, Foo { val: 7 }, Foo { val: 456 }); ```
  2. This is similar to C++ templates, but Rust partially compiles the generic 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.
  3. 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 hand-coded the data structures without the abstraction.