Understanding rust lang - structs notes

May 01, 2020

What is struct

Struct lets us to create a meaningful structure of data. Notation of defining a struct is very similar to Typescript's interfaces(and of course implementations of interfaces in other languages). This is how we define a struct:

struct Player {
    name: String,
    health: u32,
    mana: u32,
}

In order to create a struct we have to create an instance of it. Since the defined before a struct we have to follow its definition types and key-value structure.

let player1 = Player {
    name: String::from("Kamil"),
    health: 100,
    mana: 100,
};

We can't print it yet because if use println! macro we'll get error that says Player doesn't implement std::fmt::Display: Player cannot be formatted with the default formatter. Why is that? Since structs don't implement this trait, we can implement one on our own, like so. We can also annotate our struct definiton with #[derive(Debug)]. Also, we have to use non-default formatting by adding :? or different formatter inside curly brackets in println! macro. There is a great explanation on what exactly derive debug does. Here's how it goes:

#[derive(Debug)] // annotation
struct Player {
    name: String,
    health: u32,
    mana: u32,
}

let player1 = Player {
    name: String::from("Kamil"),
    health: 100,
    mana: 100,
};

println!("Players data {:?}, player1);

Update syntax

Update syntax for struct does the same thing what spread operator in JS objects/array - lets us spread(wow) key-values from one struct to the other without overwriting already defined key/keys. Here's an example:

let player1 = Player {
    name: String::from("Kamil"),
    health: 100,
    mana: 100,
};

let player2 = Player {
    name: String::from("Gustav"),
    ..player1
}; // player2 has the same health and mana values as player1

We can also just simply assign our desired value to a key, but we'll need to add mut to struct instance in order to mutate, like so:

let mut player1 = Player {
    name: String::from("Kamil"),
    health: 100,
    mana: 100,
};

player1.name = String::from("Some other name");

Adding methods to structs

Rust makes it easy to add methods to structs which are basically a functions that can refer easily to it's struct by &self syntax. It works similarly to this in JS and self in Python. We have to struct with the word impl and follow it with the name of struct that we want to implement methods on. Next step is to declare our function. We can't forget to add &self as a first parameter if we want to refer to keys and values on struct. Next param that we declare, will become a first argument when we call our method on struct. Example:

 struct Player {
    name: String,
    health: u32,
    mana: u32,
}

impl Player {
    fn multiply_by(&self, n: u32) -> u32 {
      self.health * n
    }
}

let player1 = Player {
    name: String::from("Kamil"),
    health: 100,
    mana: 100,
};

println!("Players multipied health {:?}", player1.multiply_by(3));