6 min read

Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. In today’s tutorial we are focusing on equipping you with recipes to programming with Rust and also help you define expressions, constants, and variable bindings. Let us get started:

Defining an expression

An expression, in simple words, is a statement in Rust by using which we can create logic and workflows in the program and applications. We will deep dive into understanding expressions and blocks in Rust.

Getting ready

We will require the Rust compiler and any text editor for coding.

How to do it…

Follow the ensuing steps:

  1. Create a file named expression.rs with the next code snippet.
  2. Declare the main function and create the variables x_val, y_val, and z_val:
//  main  point  of  execution fn  main()  {

//  expression

let  x_val  =  5u32;

//  y  block

let  y_val  =  {

let  x_squared  =  x_val  *  x_val;

let  x_cube  =  x_squared  *  x_val;

//  This  expression  will  be  assigned  to  `y_val`

x_cube  +  x_squared  +  x_val

};

//  z  block

let  z_val  =  {

//  The  semicolon  suppresses  this  expression  and  `()`  is assigned  to  `z`

2  *  x_val;

};

//  printing  the  final  outcomes println!("x  is  {:?}",  x_val); println!("y  is  {:?}",  y_val); println!("z  is  {:?}",  z_val);

}

You should get the ensuing output upon running the code. Please refer to the following screenshot:

How it works…

All the statements that end in a semicolon (;) are expressions. A block is a statement that has a set of statements and variables inside the {} scope. The last statement of a block is the value that will be assigned to the variable. When we close the last statement with a semicolon, it returns () to the variable.

In the preceding recipe, the first statement which is a variable named x_val , is assigned to the value 5. Second, y_val is a block that performs certain operations on the variable x_val and a few more variables, which are x_squared and x_cube that contain the squared and cubic values of the variable x_val , respectively. The variables x_squared and x_cube , will be deleted soon after the scope of the block.

The block where we declare the z_val variable has a semicolon at the last statement which assigns it to the value of (), suppressing the expression. We print out all the values in the end.

We print all the declared variables values in the end.

Defining constants

Rust provides the ability to assign and maintain constant values across the code in Rust. These values are very useful when we want to maintain a global count, such as a timer– threshold–for example. Rust provides two const keywords to perform this activity. You will learn how to deliver constant values globally in this recipe.

Getting ready

We will require the Rust compiler and any text editor for coding.

How to do it…

Follow these steps:

  1. Create a file named constant.rs with the next code snippet.
  2. Declare the global UPPERLIMIT using constant:
//  Global  variables  are  declared  outside  scopes  of  other

function

const  UPPERLIMIT:  i32  =  12;
  1. Create the is_big function by accepting a single integer as input:
//  function  to  check  if  bunber fn  is_big(n:  i32)  ->  bool  {

//  Access  constant  in  some  function

n  >  UPPERLIMIT

}
  1. In the main function, call the is_big function and perform the decision-making statement:
fn  main()  {

let  random_number  =  15;

//  Access  constant  in  the  main  thread println!("The  threshold  is  {}",  UPPERLIMIT); println!("{}  is  {}",  random_number,  if is_big(random_number)  {  "big"  }  else  {  "small"

});

//  Error!  Cannot  modify  a  `const`.

//  UPPERLIMIT  =  5;

}

You should get the following screenshot as output upon running the preceding code:

How it works…

The workflow of the recipe is fairly simple, where we have a function to check whether an integer is greater than a fixed threshold or not. The UPPERLIMIT variable defines the fixed threshold for the function, which is a constant whose value will not change in the code and is accessible throughout the program.

We assigned 15 to random_number and passed it via is_big  (integer  value); and we then get a boolean output, either true or false, as the return type of the function is a bool type. The answer to our situation is false as 15 is not bigger than 12, which the UPPERLIMIT value set as the constant. We performed this condition checking using the if…else statement in Rust.

We cannot change the UPPERLIMIT value; when attempted, it will throw an error, which is commented in the code section.

Constants declare constant values. They represent a value, not a memory address: type  =  value;

Performing variable bindings

Variable binding refers to how a variable in the Rust code is bound to a type. We will cover pattern, mutability, scope, and shadow concepts in this recipe.

Getting ready

We will require the Rust compiler and any text editor for coding.

How to do it…

Perform the following step:

  1. Create a file named binding.rs and enter a code snippet that includes declaring the main function and different variables:
fn  main()  {

//  Simplest  variable  binding let  a  =  5;

//  pattern

let  (b,  c)  =  (1,  2);

//  type  annotation let  x_val:  i32  =  5;

//  shadow  example let  y_val:  i32  =  8;

{

println!("Value  assigned  when  entering  the scope  :  {}",  y_val);  //  Prints  "8".

let  y_val  =  12;

println!("Value  modified  within  scope  :{}",  y_val);

//  Prints  "12".

}

println!("Value  which  was  assigned  first  :  {}",  y_val);

//  Prints  "8". let  y_val  =  42;

println!("New  value  assigned  :  {}",  y_val);

//Prints  "42".

}

You should get the following screenshot as output upon running the preceding code:

How it works…

The let statement is the simplest way to create a binding, where we bind a variable to a value, which is the case with variable a. To create a pattern with the let statement, we assign the pattern values to b and c values in the same pattern. Rust is a statically typed language. This means that we have to specify our types during an assignment, and at compile time, it is checked to see if it is compatible. Rust also has the type reference feature that identifies the variable type automatically at compile time. The variable_name  : type is the format we use to explicitly mention the type in Rust. We read the assignment in the following format:

x_val is a binding with the type i32 and the value 5.

Here, we declared x_val as a 32-bit signed integer. However, Rust has many different primitive integer types that begin with i for signed integers and u for unsigned integers, and the possible integer sizes are 8, 16, 32, and 64 bits.

Variable bindings have a scope that makes the variable alive only in the scope. Once it goes out of the scope, the resources are freed.

A block is a collection of statements enclosed by {}. Function definitions are also blocks! We use a block to illustrate the feature in Rust that allows variable bindings to be shadowed. This means that a later variable binding can be done with the same name, which in our case is y_val. This goes through a series of value changes, as a new binding that is currently in scope overrides the previous binding. Shadowing enables us to rebind a name to a value of a different type. This is the reason why we are able to assign new values to the immutable y_val variable in and out of the block.

This article is an extract taken from Rust Cookbook written by Vigneshwer Dhinakaran. You will find more than 80 practical recipes written in Rust that will allow you to use the code samples right away in your existing applications.

Read More

20 ways to describe programming in 5 words

Top 5 programming languages for crunching Big Data effectively

 

 


Subscribe to the weekly Packt Hub newsletter. We'll send you the results of our AI Now Survey, featuring data and insights from across the tech landscape.

* indicates required

LEAVE A REPLY

Please enter your comment!
Please enter your name here