Rust Programming – Continued

In the previous article, we have given an introduction to Rust in our previous article.  Lets go through the common programming concepts of RUST here.

Variables

By default variables are immutable. This is one of many nudges which Rust gives you to write your code in this way. It takes advantage of the safety and easy concurrency that Rust offers. However, you still have the option to make your variables mutable. Let’s explore how and why Rust encourages you to favor immutability and why sometimes opted.

When a variable is immutable, once a value is bound to a name, you can’t change that value.

Variables are immutable only by default; you can make them mutable by adding mut in front of the variable name.

fn main() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

Difference between Variable and Constant

There are a few differences between constants and variables.

  • First, you aren’t allowed to use mut with constants. Constants aren’t just immutable by default—they’re always immutable.
  • You declare constants using the const keyword instead of the let keyword, and the type of the value must be annotated.
  • Constants can be declared in any scope, including the global scope, which makes them useful for values that many parts of code need to know about.
  • The last difference is that constants may be set only to a constant expression, not the result of a function call or any other value that could only be computed at run time.

Shadowing

We can declare a new variable with the same name as a previous variable, but the new variable shadows the previous variable. In Rust the first variable is shadowed by the second, which means that the second variable’s value is what appears when the variable is used.

Shadowing is different than marking a variable as mut, because we’ll get a compile-time error if we accidentally try to reassign to this variable without using the let keyword. By using let, we can perform a few transformations on a value but have the variable be immutable after those transformations have been completed.

The other difference between mut and shadowing is that because we’re effectively creating a new variable when we use the let keyword again, we can change the type of the value but reuse the same name.

Data Types

There are two data type subsets: scalar and compound.

Rust is a statically typed language, which means that it must know the types of all variables at compile time.

A scalar type represents a single value. Rust has four primary scalar types: integers, floating-point numbers, Booleans, and characters.

Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and arrays.

fn main() {
    let tup = (500, 6.4, 1);
    let (x, y, z) = tup;
    println!("The value of y is: {}", y);
}

This program first creates a tuple and binds it to the variable tup. It then uses a pattern with let to take tup and turn it into three separate variables, x, y, and z. This is called destructuring, because it breaks the single tuple into three parts. Finally, the program prints the value of y, which is 6.4.

In addition to destructuring through pattern matching, we can access a tuple element directly by using a period (.) followed by the index of the value we want to access. For example:

fn main() {
    let x: (i32, f64, u8) = (500, 6.4, 1);
    let five_hundred = x.0;
    let six_point_four = x.1;
    let one = x.2;
}

Another way to have a collection of multiple values is with an array. Unlike a tuple, every element of an array must have the same type. Arrays in Rust are different from arrays in some other languages because arrays in Rust have a fixed length, like tuples.

Functions

Rust code uses snake case as the conventional style for function and variable names. In snake case, all letters are lowercase and underscores separate words.

fn main() {
    another_function(5);
}
fn another_function(x: i32) {
    println!("The value of x is: {}", x);
}

Rust doesn’t care where you define your functions, only that they’re defined somewhere.

In function signatures, you must declare the type of each parameter. This is a deliberate decision in Rust’s design: requiring type annotations in function definitions means the compiler almost never needs you to use them elsewhere in the code to figure out what you mean.

Statements vs Expressions

Statements are instructions that perform some action and do not return a value. Expressions evaluate to a resulting value. Let’s look at some examples.

fn main() {
    let x = (let y = 6);
}

When we run this program, the error you’ll get looks like this:

error: expected expression, found statement (let)

The let y = 6 statement does not return a value, so there isn’t anything for x to bind to. This is different from what happens in other languages, such as C and Ruby, where the assignment returns the value of the assignment. In those languages, you can write x = y = 6 and have both x and y have the value 6; that is not the case in Rust.

Expressions do not include ending semicolons. If we add a semicolon to the end of an expression, you turn it into a statement, which will then not return a value.

Comments

In Rust, comments must start with two slashes and continue until the end of the line.

// So we’re doing something complicated here, long enough that we need   
// multiple lines of comments to do it!

Control Flow

The most common constructs that let you control the flow of execution of Rust code are if expressions and loops.

An if expression allows you to branch your code depending on conditions.

fn main() {
let number = 3;
if number < 5 {
    println!("condition was true");
} else {
    println!("condition was false");
}}

Rust has three kinds of loops: loopwhile, and for

The loop keyword tells Rust to execute a block of code over and over again forever or until you explicitly tell it to stop or we can return from loop.

fn main() {
    let mut counter = 0;
    let result = loop {
        counter += 1;
        if counter == 10 {
            break counter * 2;
        }
    };
    assert_eq!(result, 20);
}

while loop: the program loops three times, counting down each time, and then, after the loop, it prints another message and exits.

fn main() {
let mut number = 3;
while number != 0 {
    println!("{}!", number);

    number = number - 1;
}
println!("LIFTOFF!!!");
}

As a more concise alternative, you can use a for loop and execute some code for each item in a collection. A for loop looks like this code

fn main() {
    let a = [10, 20, 30, 40, 50];
    for element in a.iter() {
        println!("the value is: {}", element);
    }
}

We learned about variables, scalar and compound data types, functions, comments, if expressions, and loops!

Keep reading for more on RUST.

Leave a Reply

Your email address will not be published. Required fields are marked *