Rust Generics

  • Parameters of kind "type"

  • Most commonly single capital letter (can be camel-case)

  • Can parameterize a datatype, function or impl (examples/

  • Turbofish supplies explicit type parameters


Type Inference

  • As with lifetimes, usually don't have to write generics out: compiler can match things up

  • Sometimes gets lost, though. Also, will not make choices

      // Fails to compile, for a lot of reasons.
      let s = [1, 2, 3].iter().cloned().sum();


  • Generics are implemented by erasure: a new implementation of the datatype or function is created for each place the the thing is used at a type

  • This defines an infinity of potential instantations:

      fn id<T>(x: T) -> T {
  • Inlining will happen and avoid some of these functions

  • Still, this can cause an explosion of implementations

      fn tuple<T, U, V> (x: T, y: U, z: V) -> (T, U, V)

    can have a lot of implementations floating around

Phantom Types

  • Sometimes want to have the compiler track the type of a thing just to avoid confusion

      struct Hash {
          h: u128,
    • This is the hash of some specific type: even if the h values match, if the types they were derived from do not that should fail

    • Ask the compiler to track this

        use std::marker::PhantomData;
        struct Hash<T> {
            h: u128,
            p: PhantomData<T>,
    • Now you can get typed hashes

        impl<T> Hash<T> {
            fn hash(val: T) -> Hash<T> {
                let h = unsafe { hasher(&T) };
                Hash { h, p: PhantomData }
    • examples/ for the details

Last modified: Monday, 26 April 2021, 11:35 PM