Deep Blog

Getting started with Rust: Function and struct


Hello everyone! Today we continue on our rust serie, we are going to talk about function and struct.

"Seems like a lot? Are we really going to cover all this?"

Yes and yes.

In order to do all that, we are going to need a variable, let's define that:

// We want to buy a fallout boy, so lets define a number of caps.
let caps = 5; 

We just define a variable caps of value 5.

"Wait a minute! In the previous post, didn't you said that rust was a strongly typed language?"

I did, and it's true. Let me explain you the beautiful world of type inference! At compile time, the rust compiler will try to guess the type of caps from its use (assignation or operation). I said try because, sometimes, the rust compiler will not succeded. For example, if the using of caps not allow to define its type. The type inference is here to avoid writting types when it can easily be guessed. You still can define type with this syntax:

let caps: usize /* type define here */ = 5;

That said, a variable can be shadowed. Imagine that you got the number of caps in the form of a string, it makes senses to still call it caps. That's what shadowing is about. Let me show you:

let caps = "five";
let caps = get_number_from_string(caps); // caps is now 5

Last but not least, the variable created before are immutable by default. Meaning you can't change them after declaring them. To do so, you have to explicitly tell it to the compiler:

let mut caps;
caps = 5;

In the case of shadowing, the variabke itself is not the same. We destruct it and recreate a new one. Sort of.

It may not be intuitive yet, but through practice, it will.

"Ok, but what about this get_number_from_string thing?"

Excellent transition, it's almost like if I was writting your line. get_number_from_string is a function. Let see how we can define it:

fn get_number_from_string( num: &'static str ) -> usize {...}

"HOLD ON!!!! WHAT IS THIS?????"

Ok, lets cut this. fn is the key word to indicate that we are declaring a function. get_number_from_string is the name of the function, num: &'static str is the parameter we pass to the function, in this case, a reference to a string slice. We get back to it. Then we got -> usize which indicate that we return something of type usize. And finaly the body of the function. To make it simpler, get the habits to read code outloud: the function get_number_from_string takes a number in the form of string and return an unsigned int value. I strongly think that code should be readable as a good story should. Functions are used to divided your code into unit that you can understand.

I could speak for eternity about function but you'll have to practice to understand it.

So now lets talk about struct.

"Struct, is it a shortname for strucutre?"

You are right. And guess what we use tructure for?

"We use it to... Hold things and give something a shape we can relie on?"

Right. And thats exactly what we are doing with struct.

You remember the caps variable earlier? It's this now, feel old yet?

struct CapsPurse {
  caps: usize // unsigned int is all we need. We can't have a negative value of caps.
}

//lets implements some functionalities to it.

impl CapsPurse {
  pub fn new() -> CapsPurse {
    CapsPurse { caps: 0 }
  }

  // we want to add and remove caps to it.
  pub fn add_caps(&mut self, amount: usize) {
    self.caps += amount; 
  }

  pub fn remove_caps(&mut self, amount: usize) {
    if amount <= self.caps {
      self.caps -= amount;
    }
  }
}

So lets recaps what happened here. First, we define a purse to hold our caps. We define a method to create the purse, we define methods to add or remove caps from it. As before, read out loud the method signature, it should clearly indicate what it does. Eventually, you'll encounter two unknowned elements: pub and self. pub tell to the compiler that this method can be seen from the outside of the struct. To explain correctly this concept, let us use our body to do so. Our arms are public, our face too. Everybody can sees them and, in a certain limit, touch it. On the other side, your genitals are private. You keep them from outside world in your pants. Only you can touch and sees them. Of course, there are exception in your life and for you attributes, but not in the code. So pub means that it's like an arm and when it's not here, it's like genitals: private. The other symbol, self, is refering to the structure you are calling the method on. Currently I do not see how to explain the self concept differently.

"Ok, ... Can I have a coffee with that?"

Agreed. This is not a simple matter. But hold on, the difficult part lies ahead. We will continue this later as this post is long enough like this.

I tried to make this article the more accurate and understandable as possible. If any mistake or inexactitude exist, please leave a comment. I'll be glad to correct it. Same goes if you have some advice on how I should explain things.

See you for another episode next time.

--Mathieu