I first starting learning Rust about 6 months ago, I was looking for a new language to learn when I came across it. At first I thought Rust was only meant to be a low level, systems programming language, but the more I learned, the more I realised the potential it has for high level programming and web applications. Also, along the way I learned many ways in which Rust prevents many of the typical bugs often found in applications written in other programming languages.
Let’s explore some of the benefits you get by writing your web applications in Rust.
In Rust, everything is strongly typed and checked at compile time. If a function in your program accepts a parameter of type String for example and your program compiles successfully, you are guaranteed that the value your function takes will always be a string. Therefore you can avoid writing defensive code that checks whether the parameter is of the correct type at runtime or whether the parameter is null, this makes the program faster, removes the possibility of type related errors and makes you write less code.
It goes even further though, it also enforces the type of a value used in expressions such as
if statements for example.
In other languages you can often use a non-boolean type such as a integer or a string as the condition of an
if statement. This often leads to unexpected behaviour, with Rust however you must always provide a
boolean type in this case, which ensures the result is what the programmer intended, Rust won’t try to guess whether something is false or true based on some internal rules the programmer might or might not be familiar with, the following code will just not compile in Rust :
The compiler would show the following rather helpful error :
Immutable By Default
In my view, another benefit of writing in Rust is that, by default, everything is immutable. This forces you to be explicit whenever you want to allow something to be mutable, this protects from surprises where data gets mutated when you didn’t intend it to.
Consider this example below :
The fact that we can pass our collection of dogs into a method and be guaranteed that the data hasn’t changed at all is quite mind-blowing and became an addictive feature of Rust to me. In the example above is obvious that the
walk_dogs method doesn’t mutate our collection but what if it was a method from another library? Will we then need to make sure the data hasn’t changed after the function call? Even if the method doesn’t change the value today, it may do in a future version of the library and we would not know about it.
With Rust on the other hand, we can rest assured the method won’t mutate the data because we are passing what is called an immutable reference to the
dogs_collection vector, if the
walk_dogs method tried to mutate the data in any way, this code would not compile because it would be breaking Rust ownership rules. Ownership rules is one of the things that make Rust unique, you can read more about them in the Rust book
If however we wanted the function to mutate the data, both the function signature and the code calling the function must be explicit about the intention of mutating the data by passing and accepting a mutable reference explicitly as in the following example :
Here you can see that we immediately define the variable product to be mutable using the
mut keyword, this tells Rust that we intend to mutate this variable, this introduces limitations such as that we can only have one mutable reference to a value at a time, which protects your code from data races for example. Notice that the
purchase_product function signature must also explicitly specify that it accepts a mutable reference to a Product using the
&mut Product syntax, the compiler makes sure this is the case. Finally we can see that the
product.stock property is mutated inside the function, the quantity ordered has been subtracted and the stock available for the product object is now 25.
Enums And Pattern Matching
Enums, or algebraic data types are used a lot in Rust. Let’s focus on one example to illustrate the power of combining enums with exhaustive pattern matching.
One of my favourite design decision of Rust is that it doesn’t have a
null type. A variable in Rust can never be
null. How can you express the absence of a value then? You guessed it, Enums!
Option is the de facto way of expressing the absence or the presence of a value in Rust, notice that
Option is generic,
T can be any type.
Option can be
None, if it has no value or
Some, if it does.
Let’s see an example of some code making use of the Option enum :
Here we have a struct
Customer, think of it like a class in other languages such as PHP and a function which loads a customer from a DB.
The customer with the given id might not exists in the DB, therefore we need to return an Option to allow for the possibility a non-existing customer.
Now, we can’t just assume that the customer returned by
get_customer_by_id is an instance of Customer, if we tried to do that, our program would not compile,
the compiler not only won’t allow you to assume you got an instance of Customer, it will also force you to exhaustively handle every possible variant of the enum returned by the function, making your code really robust.
Using the match operator, we are able to handle every possible outcome of calling the
Notice that we can extract data from enums, in this example the
Customer instance ends up in the variable
a in the first arm of the match expression, which we can then use on the right hand side of the
Most programming languages don’t force to exhaustively check the values of variables, lots of bugs come from assuming a function returned one type of value when sometimes does return another, Rust type system has your back and the compiler will not let you compile your code if you don’t check all the possible types.
I have only scratched the surface here, there are many more aspects of Rust which helps you write faster and safer applications. These include:
- Dependency management out of the box.
- An incredibly well-designed module system.
- No inheritance!
- Fearless concurrency