Rust: enums

Rust 0.10

Enums in Rust behave like you would expect in most C based languages. You can also implement methods on enum types. Both instance and “type” methods.

You declare these methods in the same way that you declare methods on a struct, using the impl keyword followed by the enum’s name.

Here is an example of an enum with a constructor-like method and two instance methods.

Compiling and running this program would output the following result:

Initial
Initial
NonInitial

Now let’s try something a little bit more complex. The following is a enum type I wrote for an actual application. To get more familiar with Rust, I am porting my height map generator that I used for my Ruby game project.

The following enum generates random coordinates for a particle drop point (the algorithm I use for generating the map is the particle deposition algorithm). The formula to calculate the coordinates varies depending on how many times we have called it.

Here is the enum type:

And here is how it’s called:

Contrary to the first example, when I change the state of the enum I return a new instance instead of mutating the current one.

Rust: Pattern Matching

Rust 0.10

One of Rust’s feature is pattern matching. Pattern matching is also available in languages such as Prolog, Erlang and Haskell.

In Rust you do pattern matching with the match expression. You can use pattern matching as a basic switch statement:

Here the underscore can be interpreted to mean anything. Since there is no fall through between the cases and the last one will match any values which haven’t been matched yet, it will act like a default case.

match let’s us do so much more than in many traditional C based languages.

For instance:

This example introduces variables and conditionals as well as ranges.

With variables and conditionals you can also start writing recursive matching functions. These might seem odd if you aren’t used to such constructs, but once you do you’ll find them very expressive and powerful.

Here are two simple examples, defining a factorial function and a Fibonacci function:

Pattern matching also allows us to do destructuring, which I will talk about in a later post.

Rust: Expressions

Rust 0.10

In the context of a programming language, an expression is something that can be evaluated and returns a value.

ie:

1 == 1

Is an expression that evaluates to the boolean value true.

In Rust many things are expressions; litterals, match (think pattern-matching), tuples, structs, if/else conditionals and loops are all expressions.

They will all return a value that can be used to initialize a variable or anywhere else where a value is needed.

The ; is used to suppress the return of the expression’s value and instead return (), which is known as the unit value.

Here are a couple of examples:

The first code block (delimited with brackets) will return the value of it’s last expression, inner * inner, which will be the value of the block expression itself (the whole block).

The value returned will be 4.

In the second case, the semicolon ;, symbol will suppress the value of the last statement and the value of the block expression will be ().

Here is another example:

This will print hello since the last value of the last expression in the function will be returned. Again this could be suppressed with a semicolon.

The return keyword could optionally have been used. return works as you would expect when placed anywhere within a function.

Finally here is an example of an if conditional acting as an expression:

In other languages you would have probably seen something like:

if (bool_value == true)
  int_value = 1;
else
 int_value = 0;

Here is the full code sample:

Your first cup of Rust

An introduction to the Rust programming language

Rust is a new language that is being developed by Mozilla. At the time of this writing it is still in version 0.7 and changes to the syntax and feature set can be expected before the 1.0 release.

Development is of course open-source so you can go over to the GitHub page and contribute if you wish.

Rust is being used to write Servo, Mozilla’s new parallel web browser engine. If Servo is successful it could be used to replace Gecko, although at this point this is just speculation on my part.

Why Rust

Rust is a low level systems language designed with memory safety and concurrency features. It is designed to allow easier writing of scalable applications while helping avoid common programming mistakes.

You would consider using Rust in situations where you would consider C, C++ or Go.

A short tour of Rust

Types and variables

Rust is statically typed. Variables can be declared with a type explicitly defined:

// Explicitly typed variable
let blog_post_count: int = 0;
 

We can also omit the type and Rust will infer the type itself. This is similar to using the var keyword in C#.

// Inferred variable type
let comment_count = 0;
 

Here comment_count is still statically typed. Rust will infer the type on it’s own (in this case int).

By default variables will be immutable, meaning their values can’t be changed after they are declared. Immutable variables is a concept often seen in functional programming languages.

You can define a variable to be mutable by using the mut keyword.

Here is an example of trying to modify an immutable variable and the error message that will be raised at compile time:

fn main() {
    // immutable variable
    let answer = 42;

    println(fmt!("The answer is: %d", answer));

    answer = 43;
}


[...] 7:10 error: re-assignment of immutable variable `answer`
[...]:7 answer = 43;

[...]:3:8: 3:14 note: prior assignment occurs here
[...].rs:3 let answer = 42;

error: aborting due to previous error

And here it is with the mut keyword:

fn main() {
    // mutable variable
    let mut answer = 42;

    println(fmt!("The answer is: %d", answer));

    answer = 43;

    println(fmt!("The answer is: %d", answer));
}

Which will net no compile time errors.

Compilation

But how do we compile and run Rust programs?

There are two ways to do this.

First you can run the rustc command which will compile your program into an executable. You can then run this executable from the shell like you would any other.

Secondly you can use rust run which will compile and run the program for you as a convenience. For this we use the rust tool which accepts several commands besides run. You can get more info by simply typing:

rust

Conditionals and loops

Here is an example of conditionals (if/else) and a loop.

fn main() {
  // FizzBuzz with while loop
  let mut number_to_test = 1;

  while number_to_test <= 100 {
    if number_to_test % 3 == 0 && number_to_test % 5 == 0 {
      println("FizzBuzz");
    } else if number_to_test % 3 == 0 {
      println("Fizz");
    } else if number_to_test % 5 == 0 {
      println("Buzz");
    } else {
      println(fmt!("%?", number_to_test));
    }

    number_to_test += 1;
  }
}

Rust also has a loop keyword which is an infinite loop from which you break out with break.

It also has a for loop. for has changed in the past versions and the documentation does not seem to have completely followed suite.

Code Organization

Rust code can be organized in modules.

mod custom_math {
  pub fn ceil(x: float) -> float {
    // re-invent the wheel
    return x;
  }

  pub fn floor(x: float) -> float {
    // re-invent the wheel
    return x;
  }
}

fn main() {
  custom_math::ceil(10.5);
}

You can use the use keyword to import a module in another file.

Conclusion

This was just a short basic syntax introduction but you can find out more with the official tutorial and the official site and learn more about what makes Rust tick.