# Impls and traits

💡 When we discussed about **C-like structs**, I mentioned that those are **similar to classes** in OOP languages, **but without their methods**. **impls** are **used to define methods** for Rust structs and enums.

💡 **Traits** are kind of **similar to interfaces** in OOP languages. They are used to define the functionality a type must provide. Multiple traits can be implemented for a single type.

⭐️️ But traits **can also include default implementations of methods**. Default methods can be overriden when implementing types.

## Impls without traits

```rust
struct Player {
    first_name: String,
    last_name: String,
}

impl Player {
    fn full_name(&self) -> String {
        format!("{} {}", self.first_name, self.last_name)
    }
}

fn main() {
    let player_1 = Player {
        first_name: "Rafael".to_string(),
        last_name: "Nadal".to_string(),
    };

    println!("Player 01: {}", player_1.full_name());
}

// ⭐️ Implementation must appear in the same crate as the self type

// 💡 And also in Rust, new traits can be implemented for existing types even for types like i8, f64 and etc.
// Same way existing traits can be implemented for new types you are creating.
// But we can not implement existing traits into existing types
```

## Impls & traits, without default methods

```rust
struct Player {
    first_name: String,
    last_name: String,
}

trait FullName {
    fn full_name(&self) -> String;
}

impl FullName for Player {
    fn full_name(&self) -> String {
        format!("{} {}", self.first_name, self.last_name)
    }
}

fn main() {
    let player_2 = Player {
        first_name: "Roger".to_string(),
        last_name: "Federer".to_string(),
    };

    println!("Player 02: {}", player_2.full_name());
}

// 🔎 Other than functions, traits can contain constants and types
```

## Impls, traits & default methods

```rust
trait Foo {
    fn bar(&self);
    fn baz(&self) { println!("We called baz."); }
}
```

⭐️ As you can see methods take a **special first parameter**, the type itself. It can be **either self, \&self, or \&mut self**; self if it’s a value on the stack (taking ownership), \&self if it’s a reference, and \&mut self if it’s a mutable reference.

## Impls with Associated functions

Some other languages support **static methods**. At such times, we **call a function directly** through the class without creating an object. In Rust, we call them Associated Functions. we use **::** instead of . when calling them from struct. ex. Person::new(“Elon Musk Jr”);

```rust
struct Player {
    first_name: String,
    last_name: String,
}

impl Player {
    fn new(first_name: String, last_name: String) -> Player {
        Player {
            first_name : first_name,
            last_name : last_name,
        }
    }

    fn full_name(&self) -> String {
        format!("{} {}", self.first_name, self.last_name)
    }
}

fn main() {
    let player_name = Player::new("Serena".to_string(), "Williams".to_string()).full_name();
    println!("Player: {}", player_name);
}

// we have used :: notation for `new()` and . notation for `full_name()`

// 🔎 Also in here we have used `Method Chaining`. Instead of using two statements for new() and full_name()
// calls, we can use a single statement with Method Chaining.
// ex. player.add_points(2).get_point_count();
```

## Traits with generics

```rust
trait From<T> {
    fn from(T) -> Self;
}
    impl From<u8> for u16 {
        //...
    }
    impl From<u8> for u32{
        //...
    }

//should specify after the trait name like generic functions
```

## Traits inheritance

```rust
trait Person {
    fn full_name(&self) -> String;
}

    trait Employee : Person { //Employee inherit from person trait
      fn job_title(&self) -> String;
    }

    trait ExpatEmployee : Employee + Expat { //ExpatEmployee inherit from Employee and Expat traits
      fn additional_tax(&self) -> f64;
    }
```

## Trait objects

🔎 While Rust favors static dispatch, it also supports dynamic dispatch through a mechanism called ‘trait objects.’

> [🅆](https://en.wikipedia.org/wiki/Dynamic_dispatch) **Dynamic dispatch** is the process of selecting which implementation of a polymorphic operation (method or function) to call at run time.

```rust
trait GetSound {
    fn get_sound(&self) -> String;
}

struct Cat {
    sound: String,
}
    impl GetSound for Cat {
        fn get_sound(&self) -> String {
            self.sound.clone()
        }
    }

struct Bell {
    sound: String,
}
    impl GetSound for Bell {
        fn get_sound(&self) -> String {
            self.sound.clone()
        }
    }


fn make_sound<T: GetSound>(t: &T) {
    println!("{}!", t.get_sound())
}

fn main() {
    let kitty = Cat { sound: "Meow".to_string() };
    let the_bell = Bell { sound: "Ding Dong".to_string() };

    make_sound(&kitty); // Meow!
    make_sound(&the_bell); // Ding Dong!
}
```
