# Traits in Rust

## Introduction

Traits are functionality that a type shares with other types. We use traits to define such behavior in an abstract way.

## Example

Let's say we have two structs of Pokemon and Digimon. Now both Pokemon and Digimon have a special move that we want to define as a trait. Hence we can write:

```rust
pub trait SpecialMove {
    fn sp_move (&self) -> String;
}
```

Now we can implement SpecialMove differently for our Pokemon and Digimon. Something we've done below:

```rust
struct Pokemon {
    pub id: u32,
    pub name: String,
    pub special_move: String,
    pub types: Vec<String>
}

struct Digimon {
    pub name: String,
    pub special_move: String
}

impl SpecialMove for Pokemon {
    fn sp_move (&self) -> String {
        format!("id: {}, name: {}, sp_move: {}", self.id, self.name, self.special_move)
    }
}

impl SpecialMove for Digimon {
    fn sp_move (&self) -> String {
        format!("name: {}, sp_move: {}", self.name, self.special_move)
    }
}
```

So the sp\_move fn for Pokemon outputes id, name, and special\_move, on the other hand it outputs only name, and special\_move for Digimon, because Digimon doesn't have an id field (it may have in the show, but not in this example)

So although it is a trait that carries some similarity, SpecialMove behaves different for Pokemon and Digimon, like it does in the show.

Now let's write the main fn.

```rust
fn main() {
    let charizard = Pokemon {
        id: 6,
        name: String::from("Charizard"),
        special_move: String::from("Flamethrower"),
        types: vec![String::from("Fire"), String::from("Flying")],
    };

    let black_war_greymon = Digimon {
        name: String::from("Black War Greymon"),
        special_move: String::from("Terra Destroyer"),
    };

    println!("{}", charizard.sp_move());
    println!("{}", black_war_greymon.sp_move());
}
```

Output:

```bash
id: 6, name: Charizard, sp_move: Flamethrower
name: Black War Greymon, sp_move: Terra Destroyer
```

### Default Implementations

Now traits can also have some default implementations, which exists for all the structs. Let's change the SpecialMove trait accordingly.

```rust
pub trait SpecialMove {
    fn sp_move (&self) -> String;
    fn summarize (&self) -> String {
        String::from("Every mon has a special move.")
    }
}
```

So now every implementation of SpecialMove, be it a Pokemon, Digimon or Super Saiyan, it will contain the summarize method.

So let's change the main fn accordingly to test this behavior.

```rust
fn main() {
    let charizard = Pokemon {
        id: 6,
        name: String::from("Charizard"),
        special_move: String::from("Flamethrower"),
        types: vec![String::from("Fire"), String::from("Flying")],
    };

    let black_war_greymon = Digimon {
        name: String::from("Black War Greymon"),
        special_move: String::from("Terra Destroyer"),
    };

    println!("{}", charizard.summarize());
    println!("{}", charizard.sp_move());
    println!("{}", charizard.summarize());
    println!("{}", black_war_greymon.sp_move());
}
```

Output:

```bash
Every mon has a special move.
id: 6, name: Charizard, sp_move: Flamethrower
Every mon has a special move.
name: Black War Greymon, sp_move: Terra Destroyer
```

### Passing Traits As Parameters

We can also pass traits as Parameters.

```rust
pub fn notify(mon: &impl SpecialMove) {
    println!("Notification: {}", mon.summarize());
}
```

The notify fn will take a mon as an input that implements the trait SpecialMove, and it'll printout a notification by calling the summarize method, which is a default implementation of the trait.

So let's invoke notify in main:

```rust
fn main() {
    // ...prev code
    
    println!("{}", charizard.summarize());
    println!("{}", charizard.sp_move());
    println!("{}", charizard.summarize());
    println!("{}", black_war_greymon.sp_move());
    notify(&charizard);
}
```

Output:

```bash
Every mon has a special move.
id: 6, name: Charizard, sp_move: Flamethrower
Every mon has a special move.
name: Black War Greymon, sp_move: Terra Destroyer
Notification: Every mon has a special move.
```

## Conclusion

We'll discuss little bit more about traits in the next article, specifically something called trait bounds, something that we've also briefly touched in the article about Generics. That's all for now, and cheers!
