Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What is Polymorphism?

In a dynamic language like Python, we don’t have to do anything special to allow a function to accept arguments of different types:

def print_value(val):
    print(val)

print_value(123)
print_value("hello")
print_value({})

But Rust’s static type system requires us to specify the types of our functions’ arguments:

fn print_value(val: i32) {
    println!("{}", val);
}

fn main() {
    print_value(123);
    // print_value("hello"); // ❌ Mismatched types!
}
  • If you are coming from a dynamic language like Python, the concept of polymorphism may be new to you because in dynamic languages all functions are implicitly polymorphic. But in Rust, functions only accept arguments of the exact types they expect, and we must use a mechanism like generics to support polymorphism.

  • Static typing is a powerful tool that allows the compiler to enforce correct usage of our APIs: If your function needs to be given an i32 in order to function correctly, the compiler won’t allow a user of that function to pass in a string.

  • But static typing is restrictive in cases where we want to write code that is flexible in its handling of types. In the example on this slide, we might want our print_value function to be able to print both numbers and strings, but as written it can only accept i32 values.

  • Edit print_value to make it generic using Display to print different kinds of values:

    #![allow(unused)]
    fn main() {
    fn print_value(val: impl std::fmt::Display) {
        println!("{}", val);
    }
    }