Functions and Enums in Rust

Photo by Sigmund on Unsplash

Functions and Enums in Rust

Functions are a common paradigm in various programming languages and vary in use. Some programming languages allow dynamic uses of functions and others prioritize using them in every program.

A function has different definitions depending on who you ask or what programming language they are familiar with. Although, one thing that is common about functions is their ability to compartmentalize code. Another common property is that functions allow for code reuse and influences a specific programming style set around every part of your code having a singular task to fulfil instead of being generic in the nature of their task.

Rust prioritizes functions. At least, one function will be used in any rust program. Let's take a look at how rust implements functions.

The rust compiler depends on the existence of a main function to run any rust program. Therefore, every single rust program must have a main function, even before any other function. If you are coming from a statically typed language background, that is, C, C++, Java or, C#, you should be familiar with this type of structure already.

You can define rust Functions with the fn keyword, with the name of the function following right after, opening and closing parenthesis and, a curly bracket code block to put your code in.

fn main() {
// your code here.
}

Rust functions are obviously not limited to the main function. Let's look another function example:

fn sum () {
    let add = 5 + 6;
    println!("The result is {}", add);
}

For there to be a result, the sum function has to be called inside a main function somewhere in the program, like this:

fn main() {
    sum();
}

Rust Function Parameters

Rust functions take parameters similar to functions in other programming languages, but rust has a rule: if parameters are included in a function, then, there has to be a return statement that ends that function. Let us rewrite our sum function to take parameters!

fn sum (x, y) {
 return x + y;
}

Now we also update the sum function called in the main function.

fn main(){
    let result = sum(12, 8);
    println!("Result: {}", result);
}

When we run the compile the rust program now, we expect a value, but the rust compiler raises an error that looks like this:

error: expected one of `:`, `@`, or `|`, found `)`
  --> functions.rs:11:12
   |
11 | fn sum(x, y) {
   |            ^ expected one of `:`, `@`, or `|`
   |
   = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
help: if this is a parameter name, give it a type
   |
11 | fn sum(x, y: TypeName) {
   |            ++++++++++
help: if this is a type, explicitly ignore the parameter name
   |
11 | fn sum(x, _: y) {
   |           ++

error: aborting due to 2 previous errors

Here, the rust compiler is bringing our attention to the fact that the sum function's parameters have no type annotation and no return type annotation. Parameters of rust functions have to be type annotated and, similarly the return value type of that function. To fix the bug, we then do this:

fn sum (x: u64, y: u64) -> u:64 {
 return x + y;
}

Taking a second look at previous error message, we have some other solutions we could apply but we won't be discussing yet at this point in the rust series.

We can go further to refactor the code in our sum function by removing the return keyword and the semicolon at the end of the x + y expression, since rust doesn't force you to end expressions with semicolons. The return keyword can be removed because rust then infers the return keyword, and our refactored code looks like this:

fn sum (x: u64, y: u64) -> u:64 {
    x + y
}

One last thing about rust functions is that a function that returns nothing implicitly returns a unit tuple ().

Lambda Functions

A lambda function (or anonymous function) is a concise way to create small, unnamed functions. They are often used for shot-lived operations. Rust allows us to create these lambda functions and just like their counterparts in other programming languages, lambda functions return the first and only parameter passed to it. Rust Lambda function parameters are always surrounded by |. Let's look at how to write lambda functions:

|x|{x}

A more elaborate lambda function would look like this

let sum = |x,y| x + y;

in this example we set the lambda function to a variable which we can call the same way a named function is called in rust.

sum();

Enums

Enumerations (or enums) are a set of named constants that represent distinct elements of a collection.

The syntax for rust enums looks like this:

#[derive(Debug)]
enum Color{
    Red,
    Green,
    Blue,
}

#[derive(Debug)] is used to tell the compiler that we'd like to automatically generate the debug trait for the Color enum. You should remember traits from our discussion on arrays in rust. In a later article we'll take an in-depth look into rust traits.

When implementing an enum, we access the values of an enum with the :: operator. The values of an enum are appropriately referred to as variants.

fn main() {
    let red = Color:Red;
    println!("Apples can be {:?} or {:?}", red, green);
}

Variants can also have values associated with them:

#[derive(Debug)]
enum Color{
    Red,
    Green,
    Blue,
    Rgb(u8, u8, u8);
}

We can now put our new variant value to use like so:

fn main(){
    let lavender = Color:Rgb(230, 230, 250);
    println!("My favorite color is {:?}", lavender);
}

We can go even further to refactor our color enum's code to:

#[derive(Debug)]
enum Color{
    Red,
    Green,
    Blue,
    Hsl(u16, u8, u8);
}

and implement our new variant like this:

fn main(){
    let lilac = Color:Hsl(300, 26, 21);
    println!("Lilac in HSL is written as {:?}", lilac);
}

Enums are a great way to manage multiple values in rust. There's almost no limit to how far we can go with enums and its variants. We could refactor our previous example to have enums that properly represents the values of the HSL variant in our color enum with a percentage and a degree enum. In a later article we would look at the Option enum.

Go ahead and explore rust enums and functions. See you in the next post.