Generic Traits

Traits can also be generic, just like types and functions. A trait’s parameters get concrete types when it is used.

1. ```
   #[derive(Debug)]
   ```
2. ```
   struct Foo(String);
   ```

4. ```
   impl From<u32> for Foo {
   ```
5. ```
       fn from(from: u32) -> Foo {
   ```
6. ```
           Foo(format!("Converted from integer: {from}"))
   ```
7. ```
       }
   ```
8. ```
   }
   ```

10. ```
    impl From<bool> for Foo {
    ```
11. ```
        fn from(from: bool) -> Foo {
    ```
12. ```
            Foo(format!("Converted from bool: {from}"))
    ```
13. ```
        }
    ```
14. ```
    }
    ```

16. ```
    fn main() {
    ```
17. ```
        let from_int = Foo::from(123);
    ```
18. ```
        let from_bool = Foo::from(true);
    ```
19. ```
        println!("{from_int:?}, {from_bool:?}");
    ```
20. ```
    }
    ```
  • The From trait will be covered later in the course, but its definition in the std docs is simple.
  • Implementations of the trait do not need to cover all possible type parameters. Here, Foo::from("hello") would not compile because there is no From<&str> implementation for Foo.
  • Generic traits take types as “input”, while associated types are a kind of “output” type. A trait can have multiple implementations for different input types.
  • In fact, Rust requires that at most one implementation of a trait match for any type T. Unlike some other languages, Rust has no heuristic for choosing the “most specific” match. There is work on adding this support, called specialization.