OpenSource For You

Begin Programmin­g with Rust

Rust has had its beginnings in the labs of Mozilla Research. This open source programmin­g language is extremely fast and has become very popular in recent years.

- By: Abhinav Nath Gupta The author is a software developmen­t engineer at Cleo Software India Pvt Ltd, Bengaluru, and is interested in learning programmin­g techniques and patterns as well as exploring the new and unique things that upcoming technologi­es hav

As defined by the developers themselves, Rust is a systems programmin­g language that runs blazingly fast, prevents segfaults, and guarantees thread safety. Rust is sponsored by Mozilla Research which describes it as a safe, concurrent and practical language.

Why learn Rust?

The goal of those who developed Rust was for it to be a good language for creating highly concurrent and safe systems. Rust is also designed to provide speed and safety, at the same time. Due to these features, Rust has held the title of ‘Most Loved Programmin­g Language’ in the Stack Overflow Developer survey for three straight years, starting from 2016 to 2018.

What is so unique about Rust?

Rust is intended to be a language for highly concurrent and safe systems and “programmin­g in the large,” that is, creating and maintainin­g boundaries that preserve largesyste­m integrity. This has led to a feature set with an emphasis on safety, control of memory layout and concurrenc­y.

The performanc­e of idiomatic Rust is comparable to the performanc­e of idiomatic C++. Some other unique features of Rust are:

Minimal runtime

Efficient C bindings

Efficient thread handling without race conditions between the shared data

Guaranteed memory safety

Type inference

Let’s begin with ‘Hello World!’

In the age-old tradition of programmin­g, let’s first greet the world with a ‘Hello’, i.e., a ‘Hello World’ program, as given below:

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

There is quite a lot going on in these two lines of code. Let’s begin with fn, which is how a function is defined in Rust. main is the entry point of every Rust program. println! prints text to the console and its ! indicates that it’s a macro instead of a function. A macro in Rust is a way to encapsulat­e patterns that simply can’t be done using a function abstractio­n.

Coding in Rust

There are some more ways you can use the println! macro, as shown below:

fn main() { println!("{}, {}!", "Hello", "world"); // Hello, world! println!("{0}, {1}!", "Hello", "world"); // Hello, world! println!("{greeting}, {name}!", greeting="Hello", name="world"); // Hello, world!

println!("{:?}", [1,2,3]); // [1, 2, 3] println!("{:#?}", [1,2,3]);

/* [

1, 2, 3 ] */

// format! macro is used to store the formatted STRING let x = format!("{}, {}!", "Hello", "world"); println!("{}", x); // Hello, world! }

Data types in Rust

A few basic data types in Rust are: bool: To define true or false values char: A single character value

Fixed size (bit) signed (+/-) integer types: Denoted as i8, i16, i32, i64 where the number after i represents the bit size

Fixed size (bit) unsigned (+) integer types: Denoted as u8, u16, u32, u64 where the number after u represents the bit size

Variable sized signed (+/-) integer: Represente­d as isize in code. Covers all signed integer types

Variable sized unsigned(+) integer: Represente­d as usize in code. Covers all unsigned integer types

32-bit floating point: Represente­d as f32 in code

64-bit floating point: Represente­d as f64 in code

Arrays: Fixed size list of elements of the same data type. Arrays are immutable by default and even with mut, their element count cannot be changed

Tuples: Fixed size ordered list of elements of different (or the same) data types. Tuples are also immutable by default and even with mut, their element count cannot be changed. Also, if you want to change an element’s value, the new value should have the same data type of the previous value

Slice: Used to create a reference to only part of another data structure

Str: Unsized UTF-8 sequence of Unicode string slices Examples of the above data types are shown below:

let a : bool = true; // bool type let x = ‘x’; // char type let num: i16 = 12 // fixed size signed integer type let unum: u16 = 13 // fixed size un-signed integer type let a = [1, 2, 3]; // a[0] = 1, a[1] = 2, a[2] = 3 // array type let a = (1, 1.5, true, ‘a’, “Hello, world!”); // tuple type

// example of slice let a: [i32; 4] = [1, 2, 3, 4];//Parent Array

let b: &[i32] = &a; //Slicing whole array let c = &a[0..4]; // From 0th position to 4th(excluding) let d = &a[..]; //Slicing whole array

// example of Str datatype let a = “Hello, world.”; //a: &’static str

Variable bindings, constants and statics in Rust

In the domain of Rust, the variables are immutable by default; hence, they are called variable bindings. To make them mutable, the mut keyword has been used. Rust is a statically typed language, but it doesn’t need to define the data type while declaring a variable binding. The compiler is smart enough to figure out the best data type after checking the usage. The only exception to this rule is when you declare the constants and static variables. While declaring constants and statics, you must declare the type using a colon (:). Types come after the colon.

Examples for variable bindings are given below: let a = true; // without specific declaratio­n of type let b: bool = true; // with specific declaratio­n of type let mut z = 5; // mutable variable binding

The let keyword is used in binding expression­s. We can bind a name to a value or a function.

An example of constants is shown below:

const const_1: i32 = 5;

The const keyword is used to define constants. An example of statics is given below:

static static_1: bool = true;

The static keyword is used to define the ‘global variable’ type facility.

One noteworthy difference between static and const is that the former has a fixed location in memory while const doesn’t.

Functions in Rust

Functions are declared with the keyword fn. An example of a function in Rust is given below:

fn main() { println!(“Hello, world!”); }

When passing arguments to a function, it is imperative that the data types of the arguments are declared, as shown in the example below:

fn print_sum_of_numbers(num1: i8, num2: i8) -> i32 { println!(“addition is: {}”, num1 + num2); num1+ num2 //no ; means an expression, return num1+num2 }

In Line 1 of the above snippet, ->i32 determines the return type of the value returned by the function print_sum.

In Rust, the function body can be assigned to a variable, described as function pointers, as shown in the snippet below:

// Function pointers fn pointerExa­mple(count: i32) -> i32 {

count + 1 //no ; means an expression, return count +1 }

let count1= pointerExa­mple; let count2 = count1(5); //6

Control flows in Rust

A wide array of control flows is available in Rust, including popular ones like if-else, for and while loops, as well as some control flows exclusive to Rust, i.e., match and loop. An example of these is shown in the code snippet below:

// if-else Example let comp_size = 7; if comp _size < 5 {

println!(“Small Company”); } else if comp _size < 10 {

println!(“Medium Company”); } else {

println!(“Large Company”); } // while loop example

let mut count= 0; while count < 5 { if count == 0 { println!(“Omit value : {}”, b count count += 1; continue;

} else if count == 2 { println!(“exit At : {}”, count); break; } println!(“value : {}”, count); count += 1; }

// for Loop Example for count in 0..10 { if count == 0 { println!(“Omit Value : {}”, count); continue;

} else if count == 2 { println!(“Exit At : {}”, count); break;

} println!(“value : {}”, count);

}

Another unique control flow available in Rust is loop, which is used to indicate an infinite loop, out-of-the-box. The break statement can be used to exit a loop at any time, whereas the continue statement can be used to skip the rest of the iteration and start a new one, as shown in the code snippet below:

fn main() { let mut count = 0u32;

println!(“Let’s count until infinity!”);

// Infinite loop loop {

count += 1;

if count == 3 { println!(“three”);

// Skip the rest of this iteration continue; } println!(“{}”, count);

if count == 5 { println!(“OK, that’s enough”);

// Exit this loop break; } } }

Last but not the least, let us discuss ‘match’. Rust provides pattern matching through the match keyword, which can be used in switch statements in C. An example of match is shown in the snippet below:

fn main() { let number = 13;

// TODO ^ Try different values for `number`

println!(“Tell me about {}”, number); match number {

// Match a single value

1 => println!(“One!”),

// Match several values

2 | 3 | 5 | 7 | 11 => println!(“This is a prime”), // Match an inclusive range

13...19 => println!(“A teen”),

// Handle the rest of cases

_ => println!(“Ain’t special”), }

let boolean = true;

// Match is an expression too let binary = match boolean {

// The arms of a match must cover all the possible values

false => 0, true => 1,

// TODO ^ Try commenting out one of these arms }; println!(“{} -> {}”, boolean, binary); }

This concludes our exploratio­n of the basics of the Rust programmin­g language. Rust has many more unique features to offer, like custom macros, which are beyond the scope of this article. To get more details about these, official Rust documentat­ion can be referred to.

References

[1] https://en.wikipedia.org/wiki/Rust_(programmin­g_language) [2] https://www.rust-lang.org/en-US/ [3] https://insights.stackoverf­low.com/survey/2016#technology [4] https://insights.stackoverf­low.com/survey/2017#technology [5] https://insights.stackoverf­low.com/survey/2018#technology [6] https://learning-rust.gitbooks.io/book

 ??  ??

Newspapers in English

Newspapers from India