What is Rust?

Rust is a new systems programming language.

Some of Rust's features and characteristics are:

For more information, I recommend going through The Rust Programming Language book, available for free on the Rust documentation site.

Hello world!

Creating a new executable with Cargo will produce a template with the classic hello world program.

fn main() {
    println!("Hello world!");
}

Let's break this (very simple) example up into parts, for clarity:

Variables and expressions

Declaring new variable bindings is simple, just use the let keyword:

let x = "Hello!";

Rust is an expression-oriented language, in the sense that you can even have blocks of code evaluate to a value, and use that recursively to form new expressions.

let x = {
  let z = 2 + 2;
  z
} - 5 * {
  let y = 14;
  y - 1
};

Notice how I didn't add semicolons (;) to the last expressions in each inner block. That's because Rust will give the value of that final expression to the whole block.

Declaring functions

You've already seen above how to define the main function. If you want to define other functions as you can follow the same pattern, and perhaps take in some arguments or return a value:

fn my_function(a: u8, b: String) -> u64 {
  // ...
}

In case it's not obvious, u8 and u64 are primitive types defining fixed-width unsigned integers.

String is a heap-allocated array of UTF-8 characters. Rust strings are not null-terminated; instead, they are represented as a pointer along with the length of the allocated array.

Calling functions is also a breeze:

fn main() {
  let result = my_function(123, String::from("Hello"));
  // ...
}

Note the use of String::from which creates a new owned string from an array slice of characters, such as a string literal. Allocations are easily visible in Rust.

Structs and traits

You can create your own composite data types using the struct keyword:

struct MyStruct {
  some_field: String,
  some_other_field: u32,
  // ...
}

Structures can be instantiated by specifying a value for each of their fields.

let my_struct = MyStruct {
  some_field: String::from("hi!"),
  some_other_field: 123456,
  // ...
};

Traits can be used to abstract away common behavior of data types:

trait Frobnicable {
  fn frobnicate();
}

impl Frobnicate for MyStruct {
  fn frobnicate() { /* ... */ }
}

One great advantage of traits is that you can implement your traits on types defined externally, such as built-ins or from external libraries.