# Introduction to Rust  - Part 2

#### Introduction to Functions

#### What Is a Function?

A function is a block of code that can be reused. It is used to perform specific tasks.

#### main Function

The simplest possible function that we have studied so far is the main function that is declared with `fn` keyword. This is where the program execution starts. However, it is possible to define a user-defined function.

#### User-defined Functions

The functions are customized and are written by the programmer to perform the specified tasks.

#### Define a Function

A function is declared with the fn keyword.

* Syntax The general syntax is :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671628753517/OrAD7DjeD.png align="center")
    

Naming Convention: The convention for writing a function name is in a snake case, i.e., - All letters should be lowercase

\- All words should be separated by underscores

#### Call a Function

The function executes when it is invoked.

* Syntax
    

The expression starts with the function name followed by the round brackets and then the semicolon. The function parameters may be added between the parentheses if needed.

The general syntax for invoking a function:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671630272577/L64N-HmyQ.png align="center")

Note: A user-defined function can be invoked from another function or the main function. It can be defined anywhere, above or below the main function.

If a function is invoked but its definition does not exist, the compiler will throw a compilation error, ❌, such as error\[E0425\]: cannot find function function\_xyz in this scope.

#### Example

The following example makes a user-defined function and invokes it from within the main function.

```bash
//define a function
fn display_message(){
  println!("Hi, this is my user defined function");
}
//driver function
fn main() {
     //invoke a function
      display_message();
      println!("Function ended");
}
```

Output

```bash
Hi, this is my user defined function
Function ended
```

#### Explanation

The above program comprises two functions, the user-defined function display\_message() and the driver function main() where the function is being called.

* User-defined function
    

The function `display_message()` is defined from line 2 to line 4. On line 3 a message is printed.

* Driver function
    

The driver `function main()` is defined from line 6 to line 10. On line 8 the function `display_message()` is invoked.

#### Functions With Parameters

In the previous example, a function was defined with nothing inside the round brackets. But certain functions require some information on which they should operate. For instance, a function that is expected to compute the square of a number needs to be provided with the number itself. That’s what a parameter is.

#### What Are the Parameters?

Variable or values that go in the function definition are parameters.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671630420378/D6owQ8U22.png align="center")

#### What Are Arguments?

Variables or values that go in their place in the function invocation are known as arguments.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671630443328/QwF4FnJnZ.png align="center")

#### Example

To understand the above concept, let’s look at the example below:

```bash
//function definition
fn my_func(param_1:i32, param_2:i32) {
  println!("The first value passed inside function : {}", param_1);
  println!("The second value passed inside function : {}", param_2);
}
fn main() {
  let value_1 = 1;
  let value_2 = 2;
  //calling the function
  my_func( value_1, value_2 );
  println!("Function ended");
}
```

output

```bash
The first value passed inside function : 1
The second value passed inside function : 2
Function ended
```

#### Explanation

The above program comprises two functions, the user-defined function my\_func() and the driver `function main()` where the function is being called.

* User-defined function
    

The function `my_func()` is defined from the line `2` to line `5`.

* Two parameters `param_1` and `param_2` are passed to the function.
    
* The values of passed parameters are printed online `3` and line `4`.
    
* Driver function
    
* The driver `function main()` is defined from the line `6` to line `12`.
    
    * On line `7` and line `8`, two `variables value_1` and `value_2` are defined.
        
    * On line `10`, the function is invoked while passing the value of the `variable value_1` as the first argument and that of `value_2` as the second.
        

#### Types of Arguments

* Arguments can be passed to a function in two different ways:
    
    * Pass by value
        
    * Pass by reference
        

#### Pass by Value

* Arguments Pass by Value The values from the calling function are copied to the parameters in the called function at the time the function is called. The called function can change the values of the parameter variables all it wants. This change will not be reflected in the variables passed as arguments in the calling function.
    
* Syntax The general syntax of passing arguments by value is:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671631551325/FhHo55m40.png align="center")

#### Example

The following example makes a function `square()` that takes a number n as a parameter to the function and prints the square of the function within the function.

```bash
fn square(mut n:i32){
  n = n * n;
  println!("The value of n inside function : {}", n);
}
fn main() {
  let n = 4;
  println!("The value of n before function call : {}", n);
  println!("Invoke Function");
  square(n);
  println!("\nThe value of n after function call : {}", n);
}
```

Output

```bash

The value of n before function call : 4
Invoke Function
The value of n inside function : 16
The value of n after function call : 4
```

#### Explanation

The above program is of two parts, the user-defined function square() and the driver function main() where the function is being called.

* User-defined function The function `square()`is defined from the line `1` to line `4`.
    
    On line `2` n is multiplied by itself and the value is saved in `n`. The square of the argument thus calculated is displayed on the screen online `3`.
    
* Driver function
    

The driver function `main()` is defined from line 5 to line 11.

On line 6, a variable n is defined. On line 9, the function `square()` is invoked which takes n as an argument to the function. After the function call, the value of the n is printed

Note: The value of n is not changed

#### Arguments Pass by Reference

When we want the called function to make changes to the parameters such that the changes are seen by the calling function when the call returns. The mechanism to do this is called pass arguments by reference.

* Syntax The general syntax of passing arguments by value is:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671644260921/r-S0iELBf.png align="center")

#### Example

The following example makes a function `square()` that takes a number n which is being passed by reference as a parameter to the function and prints the square of the function within the function.

```bash
fn square(n:&mut i32){
  *n = *n * *n;
  println!("The value of n inside function : {}", n);
}  
fn main() {
  let  mut n = 4;
  println!("The value of n before function call : {}", n);
  println!("Invoke Function");
  square(&mut n);
  println!("The value of n after function call : {}", n);
}
```

Output

```bash
The value of n before function call : 4
Invoke Function
The value of n inside function : 16
The value of n after function call : 16
```

#### Explanation

The above program comprises two functions, the user-defined function square() and the driver function main() where the function is being called.

#### User-defined function

* The function `square()` is defined from `line 1` to `line 4` which takes a mutable reference `(&mut)` to the parameter n of type `i32`.
    
    * On `line 2`, the square of the variable n is calculated. Since n is a reference to a variable, to access the referenced variable’s value, de-referencing is required. That is achieved with the `*n`. On the right-hand side, the value referenced by n is accessed and multiplied by itself. The assignment is also to \*n, which means the calculated result is stored in the variable that n is referencing.
        
    * The square of the function is printed on `line 3`.
        

#### Driver function

The driver function `main()` is defined from `line 5` to `line 11`.

* On `line 6`, a mutable variable n is defined.
    
* On `line 9`, the function square() is invoked.The argument to this function is & `mut` n. Here, `&` indicates that it is a reference to the variable n and `mut` indicates that n can be changed inside the function `square()`. - After the function call, the value of the n is printed.
    

Note: The value of n is changed within the function.

Note: The argument, as well as the parameter, is set as a mutable reference when the value is passed by reference. If the value is to be updated it is dereferenced first and then the update operation is performed.

#### Returning a Value From a Function

* Returning Functions
    

The functions can return a value using the return keyword inside the function definition. After the return statement is executed, the control gets back to the caller. A function invocation is replaced with the value that the call returns. Thus, that value can be saved in a variable.

* Syntax The function definition for returning a value from a function:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671646035366/yPeE7zjlK.png align="center")

There are two ways to return the value.

The general syntax for returning a value from a function using the return keyword:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671646098153/cvu_-DdTg.png align="center")

The following syntax can be used to return a value from a function without using the return keyword:

Just write the return value, and the compiler will interpret it because of the -&gt; sign in the function definition.

#### Example 1

The following example makes a function `square()` that takes a number n as a parameter to the function and stores the square of n in the local variable m and returns the variable m.

```bash
fn square(n:i32)->i32{
  println!("The value of n inside function : {}", n);
  let m = n * n;
  m // return the square of the number n
}  
fn main() {
  let  n = 4;
  println!("The value of n before function call : {}", n);
  println!("Invoke Function");
  println!("\nOutput : {}",square(n));
}
```

output

```bash
The value of n before function call : 4
Invoke Function
The value of n inside function : 4

Output : 16
```

#### Example 2

The following example makes a function square() that takes a number n as a parameter to the function and returns the square of the number n by using the return keyword.

```bash
fn square(n:i32)->i32{
  println!("The value of n inside function : {}", n);
  return n * n;
}  
fn main() {
  let  n = 4;
  println!("The value of n before function call : {}", n);
  println!("Invoke Function");
  println!("\nOutput : {}", square(n));
}
```

output

```bash
The value of n before function call : 4
Invoke Function
The value of n inside function : 4

Output : 16
```

#### Explanation

The above program is of two parts, the user-defined function square() and the driver function main() where the function is being called.

* User-defined function
    

The function `square()` is defined from `line 1` to `line 4`.

* On `line 3` n is multiplied by itself and the value is saved in n and the value of type i32 is returned using the return keyword.
    
* Driver function
    

The driver function `main()` is defined from `line 5` to `line 10`.

* On `line 6`, a variable n is defined.
    
* On `line 9`, the function square() is invoked which takes n as an argument to the function and the value of the square is printed using the `println!()` macro.
    

#### Function With Multiple Return Values

* Returning Multiple Values In system programming languages like C++ and C, it is only possible to return a single value or a pointer to an array from a function. However, Rust allows you to return multiple values using a tuple.
    
* Syntax The function definition for returning multiple values:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671646365080/rnc2NKc7m.png align="center")

The way to return a tuple from a function is to just write the tuple:

Defining a function by returning a tuple

#### Example

The following example makes a function `calculate_area_perimeter()` that takes a `x` and `y`( length and width of a rectangle) as a parameter to the function and returns a tuple `(area, perimeter)`.

```bash
// driver function
fn main() {
    let length = 4;
    let width = 3;
    println!("Rectangle lenth:{}", length);
    println!("Rectangle width:{}", width);
    let (area, perimeter) = calculate_area_perimeter(length, width);
    println!("Area: {}, Perimeter: {}", area, perimeter);
}
// calculate area and perimeter
fn calculate_area_perimeter(x: i32, y: i32) -> (i32, i32) {
    // calculate the area and perimeter of rectangle
    let area = x * y;
    let perimeter = 2 * (x + y);
    // return the area and perimeter of rectangle
    (area, perimeter)
}
```

output

```bash
Rectangle lenth:4
Rectangle width:3
Area: 12, Perimeter: 14
```

#### Explanation

The above program comprises two functions, the user-defined function `calculate_area_perimeter()` and the driver function `main()` where the function is being called.

* User-defined function The function `calculate_area_perimeter()` is defined from line 11 to line 17.
    
    * On `line 13`, the area of the rectangle is calculated by multiplying the parameters `x` and `y` and the result is saved in the area.
        
    * On `line 14`, the perimeter of the rectangle is calculated by adding parameters `x` and`y`and then multiplying the result with `2` and then, the final result is saved in the perimeter.
        
    * On `line 16`, a tuple `(area, perimeter)` is returned.
        
* Driver function The driver function `main()` is defined from the line `2` to line `9`
    
    * On `line 3`, a variable length is initialized with the value `4`.
        
    * On `line 4`, a variable width is initialized with the value 3.
        
    * On `line 5` and `6`, the value of length and width is displayed respectively.
        
    * On `line 7`, the function `calculate_area_perimeter()` is invoked which takes length and width as an argument to the function and the return value of the function is saved in a tuple.
        

#### Functions With Arrays as Arguments

It is often necessary to pass arrays as arguments to functions. Rust allows the programmer to pass arrays either by value or by reference.

\- Pass by Value  
Arrays can be passed to a function by value. What that means is that a copy of the array from the calling function is made to the called function. The general syntax for passing an array by value to a function is:

`bash fn function_name( mut array_name:[datatype;size])`

\- Example 1

The following example takes the array arr by value in the function parameter.

```rust
fn main() {
   let arr = [1, 2, 3, 4, 5];
   modify_my_array(arr);
   println!("Array in Driver Function : {:?}", arr);
}
fn modify_my_array(mut arr:[i32;5]){
   arr[2] = 8;
   arr[3] = 9;
   println!("Array in my Function : {:?}", arr);
}
```

output

```rust
Array in my Function : [1, 2, 8, 9, 5]
Array in Driver Function : [1, 2, 3, 4, 5]
```

Note: The `mut` the keyword when passing an array by value is optional. It is written along with the array name if it is desired to make local changes. It can be omitted otherwise.

#### Example 2

The following example makes a function `calculate_mean` which calculates the mean of values in an array by first taking a summation inside a for loop and then dividing the result by 5.

```rust
fn main() {
   let arr = [1, 2, 3, 4, 5];
   println!("Array in Driver Function : {:?}", arr);
   calculate_mean(arr);
}
fn calculate_mean(arr:[i32;5]){
   let mut sum = 0;
   for i in 0..5 {
       sum += arr[i];
   }
   println!("Mean of array values: {}", sum/5);
}
```

output

```rust
Array in Driver Function : [1, 2, 3, 4, 5]
Mean of array values: 3
```

#### Pass by Reference

Arrays can be passed by reference in the function parameter. In other words, changes are made in the original array and no copy is made when passed by reference in the function.

The general syntax for passing an array by reference to a function is:

```rust
fn function_name(array_name:&mut [datatype;size])
```

* Example The following example takes the array arr by reference in the function parameter.
    

```rust
fn main() {
   let mut arr = [1, 2, 3, 4, 5];
   modify_my_array(&mut arr);
   println!("Array in Driver Function : {:?}", arr);
}
fn modify_my_array(arr:&mut [i32;5]){
   arr[2] = 8;
   arr[3] = 9;
   println!("Array in my Function : {:?}", arr);
}
```

output

```rust
Array in my Function : [1, 2, 8, 9, 5]
Array in Driver Function : [1, 2, 8, 9, 5]
```

#### Return an Array

Arrays can be returned from the function.

The general syntax for returning an array from a function is:

```rust
fn function_name()->[datatype;size]
```

Note: Here the parameters can also be passed.

#### Example

The following example takes the array arr, modifies it within the function and returns it.

```rust
fn main() {
   let arr = [1, 2, 3, 4, 5];
   modify_my_array(arr);
   println!("Array in Driver Function : {:?}", arr);
   println!("Array after Function Call : {:?}", modify_my_array(arr));
}
fn modify_my_array(mut arr:[i32;5])->[i32;5]{
   arr[2] = 8;
   arr[3] = 9;
   arr
}
```

output

```rust
Array in Driver Function : [1, 2, 3, 4, 5]
Array after Function Call : [1, 2, 8, 9, 5]
```

#### What Is Recursion?

Recursion is a method of function calling in which a function calls itself during execution.

There are problems which are naturally recursively defined. For instance, the factorial of a number nnn is defined as n times the factorial of n−1

```bash
factorial(n) = n * factorial(n-1)
```

#### Parts of Recursion

In terms of programming, a recursive function must comprise two parts:

* Base case
    
    * A recursive function must contain a base case. This is a condition for the termination of execution.
        
* Recursive case
    
    * The function keeps calling itself again and again until the base case is reached.
        

#### Example

The following example computes the factorial of a number using recursion:

Note: A factorial is defined only for non-negative integer numbers.

```bash
// main function
fn main(){
   // call the function
   let n = 4;
   let fact = factorial(n);
   // print the factorial
   println!("factorial({}): {}", n, fact);
}
// define the factorial function
fn factorial(n: i64) -> i64 {
   if n == 0 { // base case
       1
   }
   else {
       n * factorial(n-1) // recursive case
   }
}
```

output

```bash
factorial(4): 24
```

#### Explanation

main function

* The main function is defined from line `2` to line `7`.
    
    * On line `4`, a call is made to function factorial with an argument passed to the function and the return value is saved in the variable fact.
        
    * On line `6`, the value of the variable fact is printed, i.e., the factorial of the number being passed as an argument.
        
* factorial function
    
    * The factorial function is defined from `line 9` to `line 16`.
        
* function definition
    
    * The function takes a parameter n of type i64.
        
* function body
    
* The recursive function is made up of two parts.
    
    * base case
        
* On line 10, the base case is defined. Since the value of n is decremented in every recursive function call, the function terminates when the value of n becomes equal to 0 on successive recursive calls.
    
* recursive case
    
* On line 14, the recursive case is defined. The value n gets multiplied with factorial(n-1) and gets pushed on the memory stack. Since the value of n is decremented in every function call, the function keeps on calling itself repeatedly until the base case is reached. As soon as the base case is reached, factorial(0) is calculated and the value is used in the immediate expression in the memory stack. The `factorial(1)` is calculated from `1∗factorial(0)`. factorial(2) is calculated from `2∗factorial(1)` This process `n∗factorial(n−1)`continues until the last value is freed from the memory stack
    

#### What Is Recursion?

Recursion is a method of function calling in which a function calls itself during execution.

There are problems which are naturally recursively defined. For instance, the factorial of a number nnn is defined as n times the factorial of n−1

```rust
factorial(n) = n * factorial(n-1)
```

#### Parts of Recursion

In terms of programming, a recursive function must comprise two parts:

* Base case
    
    * A recursive function must contain a base case. This is a condition for the termination of execution.
        
* Recursive case
    
    * The function keeps calling itself again and again until the base case is reached.
        

#### Example

The following example computes the factorial of a number using recursion:

Note: A factorial is defined only for non-negative integer numbers.

```rust
// main function
fn main(){
   // call the function
   let n = 4;
   let fact = factorial(n);
   // print the factorial
   println!("factorial({}): {}", n, fact);
}
// define the factorial function
fn factorial(n: i64) -> i64 {
   if n == 0 { // base case
       1
   }
   else {
       n * factorial(n-1) // recursive case
   }
}
```

output

```rust

factorial(4): 24
```

#### Explanation

main function

* The main function is defined from line `2` to line `7`.
    
    * On line `4`, a call is made to function factorial with an argument passed to the function and the return value is saved in the variable fact.
        
    * On line `6`, the value of the variable fact is printed, i.e., the factorial of the number being passed as an argument.
        
* factorial function
    
    * The factorial function is defined from `line 9` to `line 16`.
        
* function definition
    
    * The function takes a parameter n of type i64.
        
* function body
    
* The recursive function is made up of two parts.
    
    * base case
        
    * On line 10, the base case is defined. Since the value of n is decremented in every recursive function call, the function terminates when the value of n becomes equal to 0 on successive recursive calls.
        
* recursive case
    
* On line 14, the recursive case is defined. The value n gets multiplied with factorial(n-1) and gets pushed on the memory stack. Since the value of n is decremented in every function call, the function keeps on calling itself repeatedly until the base case is reached. As soon as the base case is reached, factorial(0) is calculated and the value is used in the immediate expression in the memory stack. The `factorial(1)` is calculated from `1∗factorial(0)`. factorial(2) is calculated from `2∗factorial(1)` This process `n∗factorial(n−1)`continues until the last value is freed from the memory stack
    

#### Introduction to Strings

* What are Strings?
    

Strings are a sequence of Unicode characters. In Rust, a String is not null-terminated unlike strings in other programming languages. They can contain null characters.

Note: Have a look at the Unicode characters

#### Types of Strings

* Strings are of two types: &str and String
    
    * String Literal `(&str)`
        
* A String literal has the following properties:
    
    * Primitive type
        
    * Immutable
        
    * The fixed-length string stored somewhere in memory
        
    * The value of string is known at compile time
        

Note: A String literal is also known as a String slice.

#### Create a String Literal

The following illustration shows how to create a primitive string:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671647844047/X5nEZrXws.png align="center")

```rust
fn main() {
  //define a primitive String variable
  let language:&str = "Rust";
  //print the String literal
  println!("String literal: {}", language);
  //print the length of the String literal
  println!("Length of the string literal: {}", language.len());
}
```

output

```rust
String literal: Rust
Length of the string literal: 4
```

#### String Object (String)

* A String object has the following properties:
    
    * A string is encoded as a UTF-8 sequence
        
    * Heap-allocated data structure
        
    * The size of this string can be modified
        
    * Not null-terminated
        
    * Encode string values that are given at the run time
        

#### Create a String Object

This method converts the empty String or a String literal to a String object using the `.tostring` method.

The following illustration creates an empty String and then converts it into the string object using the `.to_string()` method.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671647970182/ijRBx89NK.png align="center")

#### Creating an Initialized String Object

This method creates a string with some default value passed as an argument to the `from()` method.

The following illustration creates a String literal and then converts it into the String object.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671648042170/wnN450qw7.png align="center")

```rust
fn main() {
  // create an empty String
  let course1 = String::new();
  // convert String literal to String object using .to_string
  let s_course1 = course1.to_string();
  // print the String object
  println!("This is an empty string {}.", s_course1);
  // print the length of an empty String  object
  println!("This is a length of my empty string {}.", s_course1.len());

  // create a String literal
  let course2 = "Rust Programming";
  // convert String literal to string object using .to_string
  let s_course2 = course2.to_string();
  // print the String object
  println!("This is a string literal : {}.", s_course2);
  // print the length of a String object
  println!("This is a length of my string literal {}.", s_course2.len());

  // define a String object using from method
  let course3 = String::from("Rust Language");
  // print the String object
  println!("This is a string object : {}.", course3);
  // print the length of an string object
  println!("This is the length of my string object {}.", course3.len());
}
```

Note: len() is a built-in function used to find the length of a String literal and String object.

#### Core Methods of String Objects

Some of the core methods are discussed in this lesson. You can find a list of all the String methods in Rust documentation of Strings.

#### Capacity in Bytes

The capacity gives the number of bytes allocated to the String, unlike len which gives the number of bytes taken by the String object. To get the capacity of a variable in bytes, use the built-in function `capacity()`.

* Syntax
    

The general syntax is:

`str.capacity()`

Here str is the string whose capacity is to be found.

Note: The length of the String will always be less than or equal to the capacity.

```rust
fn main() {
  // define a growable string variable
  let course = String::from("Rust");
  println!("This is a beginner course in {}.", course);
  //capacity in bytes
  println!("Capacity: {}.", course.capacity());
}
```

output

```rust
This is a beginner course in Rust.
Capacity: 4.
```

#### Finding a Substring

To find if one string contains another string, use the contains() built-in function.

* Syntax The general syntax is :
    

```rust
str.contains("sub_str")
```

Here str is the original string and "sub\_str" is a substring which is to be found in a string.

```rust
fn main() {
  // define a growable string variable
  let str = String::from("Rust Programming"); 
  let sub_str = String::from("Rust"); 
  println!("This is a beginner course in {}.", str);
  // find if string contains a substring
  println!("{} is a substring of {}: {}.", sub_str, str, str.contains("Rust"));
}
```

output

```rust
This is a beginner course in Rust Programming.
Rust is a substring of Rust Programming: true.
```

#### Replace a Substring

To replace all occurrences of one substring within a String object with another String, use the replace() built-in function.

* Syntax
    

The general syntax is :

```rust
str.replace(replace_from, replace_to)
```

Here str is the original string, `replace_from` is the value which is to be replaced in the string str and replace\_to is the value the string is converted to.

```rust
fn main() {
  // define a growable string variable
  let str = String::from("Rust Programming"); 
  let replace_from = "Programming";
  let replace_to = "Language"; 
  // find if string contains a substring
  let result = str.replace(replace_from, replace_to);
  println!("{} now becomes {}.", str, result);
}
```

output

```rust

Rust Programming now becomes Rust Language.
```

#### Trim a String

To trim a string use the function trim(). It is used to remove leading and trailing whitespaces in a string.

* Syntax The general syntax is :
    

```rust
string.trim()
```

Note: The trim function does not remove the space between the string.

```rust
fn main() {
   let string = "   Rust     Programming     ".to_string();
   let trim_string = string.trim(); 
   // get characters at 5,6,7,8,9,10 and 11 indexes
   println!("Trimmed_string : {}", trim_string);
}
```

output

```rust
Trimmed_string : Rust     Programming
```

#### Iterating Over Strings

The following methods describe three different ways of traversing a String:

* Tokenizing a String Object A String object can be tokenized on a whitespace or a character token.
    

#### Tokenizing to Separate on Whitespaces

`split_whitespace` is used to split a String on the occurrence of whitespace. Loop through the String to split on whitespaces using a for a loop.

Syntax

The general syntax is:

```rust
for found in  str.split_whitespace(){
    println!("{}", found);
}
```

Here str is the original String which is to be traversed, `split_whitespace()` is a built-in keyword to split a string on whitespaces, for is used to traverse over the String and print it as soon as the whitespace is found and found is an iterator over the String.

```rust
fn main() {
  // define a String object
  let str = String::from("Rust Programming"); 
  // split on whitespace
  for token in str.split_whitespace(){
      println!("{}", token);
  }
}
```

output

```rust
Rust
Programming
```

#### Tokenizing to Split on a Custom Character

split method is used to split a sentence on some token. The token is specified in the split method. This would be useful to process comma-separated data, which is a common programming task.

* Syntax
    

The general syntax is:

```rust
for found in str.split(","){
    println!("{}", found);
}
```

Here str is the original String which is to be traversed,str.split() is a built-in method which takes a parameter, i.e., any delimiter and split the sentence on that parameter, for is used to traverse over the String and print a word before the token.

```rust
fn main() {
  // define a String object
  let str = String::from("CloudNativeFolks, course on, Rust, Programming");  
  // split on token
  for token in str.split(","){
      println!("{}", token);
  }
}
```

output

```rust
 CloudNativeFolks 
 course on
 Rust
 Programming
```

#### Iterating Over the String Object

chars method allows iterating over each element in a String using a for a loop.

* Syntax The general syntax is:
    

```rust
for found in  str.chars(){
    println!("{}", found);
}
```

Here `str` is the original String which is to be traversed, `str.chars()` is a built-in keyword to denote letters in a String, for is used to traverse over the String and print every literal, and found is an iterator over the String.

```rust
fn main() {
  // define a String object
  let str = String::from("Rust Programming");  
  // split on literal
  for token in str.chars(){
      println!("{}", token);
  }
}
```

output

```rust
R
u
s
t
 
P
r
o
g
r
a
m
m
i
n
g
```

#### Updating a String

An existing string can be updated by appending a character or a string.

💡 Why not make a new String rather than updating an existing one?

Updating an existing String is useful when you want to make changes to an existing String at run time rather than compile one like, in situations where changes are made to the String on a condition.

#### Push a Single Character

There are cases when it is required to update a string by pushing a single character. One example is to create a string which contains a single character repeated N times on a particular condition. Rust helps you do it by using the push method.

* Steps to push a character to a String:
    
    * Make a mutable string variable.
        
    * To push a single Unicode character to a String object, pass a character within the push() built-in method.
        
    * The following code shows how to do it!
        

```rust
     fn main() {
 // define a String object
 let mut course = String::from("Rus");
 // push a character
 course.push('t');
 println!("This is a beginner course in {}.", course);
}
```

output

```rust
This is a beginner course in Rust.
```

There are cases when it is required to grow a String by concatenating a new String to an existing String. Rust helps you do it by using the `push`,`+` operator and the format! macro method.

#### Push a String

Rust helps you to grow a String object using a `push_str` method.

* Steps to push a String to a String:
    
    * Make a mutable String variable.
        
    * To push a string to a growable string variable, pass a character within the `push_str()` built-in method.
        

The following code shows how to do it

```rust
fn main() {
  // define a string object
  let mut course = String::from("Rust");
  // push a string
  course.push_str(" Programming");
  println!("This is a beginner course in {}.", course);
}
```

output

```rust
This is a beginner course in Rust Programming.
```

#### Concatenation Using `+` Operator

A String can be concatenated to another String using the `+` operator. Note: The right-hand-side operand is to borrowed while concatenating using + operator. The following code shows how to do it!

```rust
#[allow(unused_variables, unused_mut)]
fn main(){
   // define a String object 
   let course = "Rust".to_string();
   // define a String object
   let course_type = " beginner course".to_string();
   // concatenate using the + operator
   let result = course + &course_type;
   println!("{}", result);
}
```

output

```rust
Rust beginner course
```

#### Format Macro

To add two or more String objects together, there is a macro called format!. It takes variables or values and merges them in a single String.

> ```rust
> Note: The format! macro allows concatenating in the desired order by passing a positive integer number within the placeholder. 
> If the number is not mentioned it will concatenate in the order of the values written.
> 
> To display the result of format! macro, the result is to be saved in a variable.
> ```

The following code shows how to do it!

```rust
fn main(){
  
   let course = "Rust".to_string();
   let _course_type = "beginner course".to_string();
   // default format macro 
   let result = format!("{} {}", course, _course_type);
   // passing value in the placeholder in the format macro 
   let result = format!("{1} {0}", course,_course_type);
   println!("{}", result);
}
```

output

```rust
beginner course Rust
```

#### Slicing a String

What Is Slicing?

* Slicing is used to get a portion of a string value.
    
* Syntax The general syntax is:
    

```rust
let slice = &string[start_index..end_index]
```

Here,

* start\_index and end\_index are the positions of starting and ending index of the original array respectively.
    
    * Note: The start\_index is inclusive and end index is exclusive
        
* `&` indicates that the variable slice borrows the string.
    
    * Note: The minimum value of `start_index` is `0` and the maximum value is the size of the string
        

```rust
   fn main() {
   let string = "Rust Programming".to_string();
   let slice = &string[5..12]; 
   // get characters at 5,6,7,8,9,10 and 11 indexes
   println!("Slice : {}", slice);
}
```

output

```rust
Slice : Program
```

#### functions and Strings

#### Passing Primitive String - String Literal `(&str)`

String literals are passed to the functions just like other variables. They can be reused after the function call.

```rust
fn main(){
   let course: &str = "Rust Programming";
   display_course_name(course); 
   println!("{}",course); // string literal is used after the function call
}
fn display_course_name(my_course: &str){
   println!("Course : {}", my_course);
}
```

output

```rust
Course : Rust Programming
Rust Programming
```

#### Passing Growable String - String Object `(String)`

While passing String Objects to functions, they cannot be reused again because the value once passed gets moved to that function’s scope and cannot be reused.

```rust
fn main(){
   let course:String = String::from("Rust Programming");
   display_course_name(course); 
   //cannot access course after display
}
fn display_course_name(my_course:String){
   println!("Course : {}", my_course);
}
```

output

```rust
Course : Rust Programming
```

#### Introduction to Vectors

* What are Vectors?
    

Vectors are resizable arrays meaning(they can grow or shrink in size).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671648904953/4YtYcWvJ4.png align="center")

#### Create Vectors

* There are two ways to create a vector:
    
* Syntax
    
    * To create a vector write the vector macro `(vec!)` followed by the elements of the vector enclosed in square brackets
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671649271048/zWgGVT_wG.png align="center")

t is optional to define the type and size of the vector enclosed within angular brackets. Use the vector macro`(vec!)` before defining the elements of the vector.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671649902465/VKWhimsPR.png align="center")

```rust
fn main() {
   //define a vector of size 4
   let my_vec = vec![1, 2, 3, 4, 5];
   //print the vector
   println!("{:?}", my_vec);
}
```

output

```rust
[1, 2, 3, 4, 5]
```

Note: Like arrays can be displayed on the screen using the println!() macro.

#### Access an Element of a Vector

* Any value of the vector can be accessed by writing the vector name followed by the index number enclosed within square brackets `[ ]`.
    

```rust
fn main() {
   //define a vector of size 4
   let my_vec = vec![1, 2, 3, 4, 5];
   //access a particular value
   println!("{}", my_vec[0]);
}
```

output

```rust
1
```

Note: If you try to access an index that does not exist, the compiler will give out of bound access error, ❌.

This is illustrated in the code below:

```rust
fn main() {
   //define a vector of size 4
   let my_vec = vec![1, 2, 3, 4, 5];
   //access a particular value
   eprintln!("{}", my_vec[9]);
}
```

output

```rust
  thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 9', /rustc/73528e339aae0f17a15ffa49a8ac608f50c6cf14/src/libcore/slice/mod.rs:2796:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
```

To cater to out-of-bound exceptions, you can use a None keyword.

```rust
fn main() {
    let my_vec = vec![1, 2, 3,4,5];
    match my_vec.get(9) {
        Some(x) => println!("Value at given index:{}", x),
        None => println!("Sorry, you are accessing a value out of bound")
    }
}
```

output

```rust
Sorry, you are accessing a value out of bound
```

#### Print the Vector

```rust
fn main() {   
    println!("Print using debug trait");   
    let my_vec = vec![1, 2, 3,4,5];
    //using debug trait 
    println!("Vector : {:?}", my_vec);
    println!("Print using for loop"); 
    // using loop
    let mut index = 0;
    for i in my_vec {
        println!("Element at index {}:{} ", index, i);
        index = index+1;
    }
}
```

output

```rust
Print using debug trait
Vector : [1, 2, 3, 4, 5]
Print using for loop
Element at index 0:1 
Element at index 1:2 
Element at index 2:3 
Element at index 3:4 
Element at index 4:5
```

#### Methods of Vectors

The methods of vectors are summarized in the chart below:

| # | method | explaination |
| --- | --- | --- |
| 1 | Vec::new() | creates a new vector |
| 2 | .push() | push a value |
| 3 | .pop() | pop a value |
| 4 | .contains() | returns true if the vector |
| contains a particular value |  |  |
| 5 | remove(i) | remove value at given index |
| 6 | .len() | return len of the vector |

The following code demonstrates each of the above methods:

```rust
fn main() {

   let mut my_vec = Vec::new();

   println!("Empty Vector : {:?}", my_vec);

   my_vec.push(1);

   my_vec.push(2);

   my_vec.push(3);

   println!("Pushed elements 1 , 2 , 3 : {:?}", my_vec);

   my_vec.pop();

   println!("Popped value: {}", 3);

   println!("Popped element at last index : {:?}", my_vec);

   my_vec.remove(1);

   println!("Removed value: {}", 2);

   println!("Removed element at index 1 : {:?}", my_vec);

   println!("Size of vector is :{}", my_vec.len());

   println!("Does my vector contains 1 : {}", my_vec.contains(&1));

}
```

output

```rust
Empty Vector : []
Pushed elements 1 , 2 , 3 : [1, 2, 3]
Popped value: 3
Popped element at last index : [1, 2]
Removed value: 2
Removed element at index 1 : [1]
Size of vector is :1
Does my vector contains 1 : true
```

Note: When using the .contains function, consider borrowing the value.

#### Iterating Over a Vector

If it is desired to access each element of a vector, then it is possible to iterate over the elements of a vector using `iter()` rather than using the indexes to access a particular element of a vector using the square bracket notation

#### Iterate Using `.iter()` Built-in Method

* we learned to remove an element given an index. However, to remove a particular element, we first need to find the index of that element and then call the remove function passing that index.
    
* For this we can use the `.iter().position(|&e| e == element_name).unwrap()`.
    

Here,

* `iter()` is the built-in function that iterates over the elements of the vector.
    
* `.position` is a built-in function that takes the element name to get the position of that element in the vector, i.e., `(|&e| e == element_name)` defines a variable e with the value equal to the name of the element that we want to find.
    
* `.unwrap()` is the built-in function.
    

```rust
fn main() {
    // defines a mutable vector
    let mut my_vec = vec![1, 2, 3, 4, 5];
    // define the value to be removed
    let value = 2; 
    // get the index of the value in the vector
    let index = my_vec.iter().position(|&r| r == value).unwrap();
    // call the built-in remove method
    my_vec.remove(index);
    // print the updated vector
    println!("Updated Vector: {:?}", my_vec);
}
```

output

```rust
Updated Vector: [1, 3, 4, 5]
```

As you can see the value 2 is removed from the vector. you’ll learn how the iterator function helps to loop through each element in the vector index-by-index.

#### Loop Through the Values

* Define a vector variable.
    
* The values of the vector within the loop can be traversed using `.iter()`.
    

📝If you don’t write `.iter()` within the loop defination, a simple for loop will give you the same result.

```rust

fn main() {
  // define a vector of size 5   
  let my_vec = vec![1, 2, 3, 4, 5];
  // using loop
  let mut index = 0;
  for i in my_vec.iter(){ // it works even if .iter() is not written
      println!("Element at index {}:{} ", index, i);
      index = index + 1;
  }
}
```

output

```rust
Element at index 0:1 
Element at index 1:2 
Element at index 2:3 
Element at index 3:4 
Element at index 4:5
```

#### Loops and Mutate Values

* Define a mutable vector variable
    
* The values of the vector within the loop can be changed using `.iter_mut()`.
    

```rust
fn main() {
 // define a vector of size 5
 let mut my_vec = vec![1, 2, 3, 4, 5];
 println!("Initial Vector : {:?}", my_vec);
 for x in my_vec.iter_mut(){
     *x *= 3;
 }
 // print the updated vector
 println!("Updated Vector : {:?}", my_vec);
}
```

The following illustration shows how the above code works:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671650165175/XKn0CAnLr.png align="center")

#### Slicing a Vector

* Get Slice Imagine a situation where you need to get a portion of a vector. Rust allows you to borrow the slice of the vector instead of using the whole vector.
    
* Syntax Slice is a two-word object. The first word is a pointer to the data, and the second word is the length of the slice.
    

```rust
fn main() {
   // define a vector of size 5
   let my_vec = vec![1, 2, 3, 4, 5];
   let slice:&[i32] = &my_vec[2..4];
   // print the vector
   println!("Slice of the vector : {:?}",slice);
}
```

output

```rust
Slice of the vector : [3, 4]
```

#### Introduction to Structs

#### What Are Structs?

* Structs consist of related items that potentially have different data types.
    
* Structs are similar to tuples in this regard. However, unlike tuples, you must define the data type of the item within the struct
    
* Structs help to create custom data types.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651506483/t-TGgcV2J.png align="center")

* Let’s consider a real-life example. You know that a rectangle has two measurements, width and height. Suppose you have several rectangles which you can name. Once you have declared rectangle items within the struct, you can initialize the values according to the type of rectangle. Suppose the dimensions of a rectangle may vary according to the colour of the rectangle.
    

#### Declare a Struct

Structs are declared using a struct keyword followed by the name of the struct and then the body of the struct enclosed within curly braces. Within the body, the items of the struct are defined as a key: value pair where keys are the items of the struct and value is the data type of each item.

Note: The struct construct can be declared anywhere, above or below the function that initializes it.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651451992/jSR0Cd9K4.png align="center")

* Naming Convention:
    
    * The name of the struct should be in PascalCase, meaning, the first letter of each word in a compound word is capitalized.
        
    * If this case is not followed, a warning, ⚠️, is generated by the compiler.
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651394118/Qjj7-9qYZ.png align="center")

Note: The order in which you assign values to items does not matter.

#### Access Values from a Struct

To access any value from the struct write the struct name followed by the . operator and then the name of the item to be accessed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651338443/Sdb8hBQyw.png align="center")

Note: A struct instance is immutable by default. Therefore it cannot be updated unless made mutable. However, the values can be accessed.

#### Update a Struct Instance

A struct instance can be made mutable by adding a mut keyword after the let followed by the instantiation of the struct. Now that the struct instance is mutable, any item can be accessed using the dot operator and the value of the item can be updated.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651309055/6QHPl3nnw.png align="center")

* Example
    

The following example creates a struct named Course and defines three items of it: course name, course level, and course code.

```rust
//declare a struct
struct Course {
   code:i32,
   name:String,
   level:String, 
}

fn main() {
   //initialize
   let mut course1 = Course  {
      name:String::from("Rust"),
      level:String::from("beginner"),
      code:130,
   };
   let course2 = Course  {
      name:String::from("Javascript"),
      level:String::from("beginner"),
      code:122,
   };
   //access
   println!("Name:{}, Level:{}, code: {}", course1.name, course1.level, course1.code);
   println!("Name:{}, Level:{}, code: {}", course2.name, course2.level, course2.code); 
   //update
   course1.name = "Java".to_string();
   course1.code = 134;
   println!("Name:{}, Level:{} ,code: {}", course1.name, course1.level, course1.code);
}
```

output

```rust
Name:Rust, Level:beginner, code: 130
Name:Javascript, Level:beginner, code: 122
Name:Java, Level:beginner ,code: 134
```

#### Functions and Structs

* Often, we need to pass a struct instance to a function. For example, in the previous lesson, every time we wanted to print a new struct instance we had to write a new print macro to print it. However, we can avoid multiple print statements by writing one print statement within a function and calling it when we need it.
    

#### Pass Structs to a Function

* The structs can be passed to a function and the function can be invoked when required.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651653268/LP7SXFEFv.png align="center")
    

```rust
//declare a struct
struct Course {
   code:i32,
   name:String,
   level:String, 
}
fn display_mycourse_info(c:Course) {
println!("Name:{}, Level:{} ,code: {}", c .name, c .level, c.code);
}
fn main() {
   //initialize
   let course1 = Course  {
      name:String::from("Rust"),
      level:String::from("beginner"),
      code:130
   };
   display_mycourse_info(course1);
    let course2 = Course  {
      name:String::from("Java"),
      level:String::from("beginner"),
      code:130
   };
   display_mycourse_info(course2);
}
```

output

```rust
Name:Rust, Level:beginner ,code: 130
Name:Java, Level:beginner ,code: 130
```

#### Return Structs From a Function

Structs can also be returned from the functions.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671651601314/PUd7hCCoV.png align="center")

```rust
//declare a struct
struct Course {
   code:i32,
   name:String,
   level:String, 
}
fn return_rust_course_info(c1:Course, c2:Course)-> Course{
   println!("I got into function and return values from there");
   if c1.name == "Rust" {
      return c1;
   }
   else{
      return c2;
   }
}

fn main() {
   //initialize
   let course1 = Course  {
      name:String::from("Rust"),
      level:String::from("beginner"),
      code:130
   };
    let course2 = Course  {
      name:String::from("Java"),
      level:String::from("beginner"),
      code:130
   };
  
  let choose_course = return_rust_course_info(course1, course2);
  println!("I choose to learn {} {} course with code:{}", choose_course.name, choose_course.level, choose_course.code);
}
```

output

```rust
I got into function and return values from there
I choose to learn Rust beginner course with code:130
```

#### What Are Static Methods?

* Static methods are the ones that can be invoked without instantiating the struct.
    

#### Declare a Static Method

The following illustration explains how to declare a static method within the impl construct.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134246151/50f932cf-9075-430e-be5d-38398cfc1ab3.png align="center")

Note: If the construct is declared with an impl keyword, it must have one or both types of methods, static or non-static.

#### Invoke a Static Method

A static method can be invoked by following the struct name with the membership operator:: followed by the method name : 

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134314385/5d7d6680-b3ff-45c7-9592-28f51ed9bac7.png align="center")

#### Example

The following example creates a static method `my_static_method` and invokes it from the main function.

```rust
// declare a struct

struct Course {

   name: String,

   level:String,

   code: i32,

}

impl Course {

   // static method

   fn my_static_method(n: String, l: String, c:i32) -> Course {

      Course { 

      name: n, 

      level:l,

      code:c

       }

   }

   //display

   fn display(&self){

      println!("name :{} code:{} of type: {}", self.name, self.code, self.level );

   }

}

fn main(){

   // call the static method

   let c1 = Course::my_static_method("Rust".to_string(), "beginner".to_string(), 132);

   c1.display();

}

```

output

```rust
name :Rust code:132 of type: beginner
```

#### Tuple Structs

What Are Tuple Structs?

* Tuple Structs are a data type that is a hybrid between a tuple and a struct.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134526304/f6ea28c3-93de-4203-a11f-2e1a247eccdb.png align="center")

Why a tuple struct?

In the example above, when it is only a tuple we don’t know explicitly what each item in the tuple means. But when it is a tuple struct, we can assign a name to each item.

#### Define a Tuple Struct

* Tuples can be of type struct by adding the struct keyword before the tuple name, followed by the data type of the variables enclosed within round brackets.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134556978/928dcce8-04b4-40fa-865f-524ddf9e0c37.png align="center")

#### Initialize a Tuple Struct

A tuple struct can be initialized like a tuple.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134580947/443b8a4d-3761-486a-acd8-71e45059946f.png align="center")

#### Access a Tuple Struct

The tuple struct can be accessed using a `.` operator like a traditional struct.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134628884/ba80bbdf-4b5e-49ce-993b-900b95030677.png align="center")

#### Example

The following example declares a tuple struct named FruitQuantity.

```rust
//define a tuple struct
struct FruitQuantity(String, i32);
// main function
fn main() {
    // create an instance
    let r1 = FruitQuantity("oranges".to_string(), 12);
    // access values of a tuple struct
    println!("r1--name:{} quantity:{}", r1.0, r1.1);
    // create an instance
    let r2 = FruitQuantity("mangoes".to_string(), 13);
    // access values of a tuple struct
    println!("r2--name:{} quantity:{}", r2.0, r2.1);   
}
```

output

```rust
r1--name:oranges quantity:12
r2--name:mangoes quantity:13
```

[main.rs](http://main.rs)

```rust
#[allow(unused_variables, unused_mut)]
use std::fs::File;
use std::io::{BufRead, BufReader};
 
fn main() {
   let filename = "sublist_input.txt";
   // Open the file in read-only mode (ignoring errors).
   let file = File::open(filename).unwrap();
   let reader = BufReader::new(file);
   let mut vec1 = vec![];
   let mut vec2 = vec![];
   // Read the file line by line using the lines() iterator from std::io::BufRead.
   for (index, line) in reader.lines().enumerate() {
       let line = line.unwrap(); // Ignore errors.
       // Show the line and its number.
       println!("{}", line.to_string());
       let mystr = line.to_string();
       let bar: Vec<&str> = mystr.split(", ").collect();
       let baz = bar.iter().map(|x| x.parse::<i64>());

       for x in baz {
           match x {
               Ok(i) => if index % 2 == 0 {vec1.push(i)} else {vec2.push(i)},
               Err(_) => println!("parse failed {:?}", x),
           }
       }
       if index % 2 == 1{
        println!("vec 1{:?}", vec1);  
        println!("vec 2{:?}", vec2);   
   
        println!("{}", Comparison::Superlist == sublist(&vec1, &vec1));
        println!("{}", Comparison::Equal == sublist(&vec1, &vec1));
        println!("{}", Comparison::Superlist == sublist(&vec2, &vec1));
        println!("{}", Comparison::Sublist == sublist(&vec1, &vec2));
        println!("{}", Comparison::Unequal == sublist(&[1, 2, 1, 2, 3], &[1, 2, 3, 1, 2, 3, 2, 3, 2, 1]));
       }

}
}


#[derive(Debug, PartialEq, Eq)]
enum Comparison {
    Equal,
    Sublist,
    Superlist,
    Unequal,
}


fn sublist(a : &[i64], b : &[i64]) -> Comparison {
    if a == b {
        Comparison::Equal
    } else if contains(a, b) {
        Comparison::Superlist
    } else if contains(b, a) {
        Comparison::Sublist
    } else {
        Comparison::Unequal
    }
}

fn contains(a: &[i64], b: &[i64]) -> bool {
    if a.len() < b.len() {
        return false;
    }

    if a.starts_with(b) {
        return true;
    }

    contains(&a[1..], b)
}
```

sublist\_input.txt

```rust
3, 4, 5
1, 2, 3, 4, 5
```

output

```rust
3, 4, 5
1, 2, 3, 4, 5
vec 1[3, 4, 5]
vec 2[1, 2, 3, 4, 5]
false
true
true
true
true
```

#### Introduction to Enums

* What Are Enums? Enum is a custom data type that is composed of variants.
    

```rust
 Variants are values which are definite.
```

The key is to enumerate all possible values and select one of the values from the list.

* Let’s consider a real-life example to understand the concept of enums. The traffic signal can have  
    only three possible states: red, yellow and green for stop, slow down, and go respectively.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134779694/62110036-0969-4fb0-9576-3a6d9961d9b6.png align="center")

#### Declare an Enum

Enums are declared using the enum keyword followed by the name of the enum and then the body of the enum enclosed within curly braces `{` `}`. Within the curly braces, the variants of the enum are defined.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134880873/93c2afa9-22c7-4d97-bccf-4365504982a9.png align="center")

Naming Convention

* The name of the enum and it’s variants are written in CamelCase.
    

#### Initialize an Enum

Enums are initialized using the name of the enum followed by a double colon`(::)` and then specify the name of the variant of the enum.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134885836/47496517-c61c-455d-89d0-9f8f05fe6748.png align="center")

Note: To print the values of an enum, write `#[derive(Debug)]` at the beginning of the program code. Use the debug `trait{:?}` for printing the variants.

* Example The following example declares an `enum` named `KnightMoves`.
    

![](https://upload.wikimedia.org/wikipedia/commons/0/0b/Knight_%28chess%29_movements.gif align="left")

Note: To keep things simple, two variants are mentioned. However, a Knight in chess can move be in four directions. It moves to a square that is two squares away horizontally and one square vertically, or two squares vertically and one square horizontally

```rust
// make this `enum` printable with `fmt::Debug`.

#[derive(Debug)]

enum KnightMove{

   Horizontal, Vertical

}

fn main() {

   // use enum

   let horizontal_move = KnightMove::Horizontal;

   let vertical_move = KnightMove::Vertical;

   // print the enum values

   println!("Move 1: {:?}", horizontal_move);

   println!("Move 2: {:?}", vertical_move);

}



```

output

```rust
Move 1: Horizontal
Move 2: Vertical

```

#### Enums With Data Type

By default, the Rust compiler infers the data type for all variants of an enum. However, it is possible to use different data types for different variants of an enum.

#### Syntax

* The data type can be added to each variant enclosed within round brackets `()`.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672134956069/c789f2cf-d1f2-41d8-873e-a28d90e3cbb1.png align="center")
    
* Example The following example makes an enum KnightMove having two variants Horizontal and Vertical both of type String.
    

```rust
// make this `enum` printable with `fmt::Debug`.

#[derive(Debug)]

enum KnightMove{

   Horizontal(String), Vertical(String)

}

fn main() {

   // invoke an enum

   let horizontal_move = KnightMove::Horizontal("Left".to_string());

   let vertical_move = KnightMove::Vertical("Down".to_string());

   // print enum

   println!("Move 1: {:?}", horizontal_move);

   println!("Movw 2: {:?}", vertical_move);

}
```

output

```rust
Move 1: Horizontal("Left")
Movw 2: Vertical("Down")
```

#### Methods of Enums

* What Are Methods? Just like structs, methods are functions specific to enums.
    
* Syntax
    

To define methods of `enum` write the functions within the `impl` followed by the `enum` name and then the functions within the `impl` block.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672135023442/c8457994-6b93-4593-b647-bf292c92b437.png align="center")

* Move `enum` related logic in the `impl` construct
    
* Example The example below declares an `enum`, named `TrafficSignal` and defines an enum method `is_stop` within the `impl` construct:
    

```rust
#![allow(dead_code)]
#[derive(Debug)]
// declare an enum
enum TrafficSignal{
  Red, Green, Yellow
}
//implement a Traffic Signal methods
impl TrafficSignal{
  // if the signal is red then return
   fn is_stop(&self)->bool{
     match self{
       TrafficSignal::Red=>return true,
       _=>return false
     }
   }
}
fn main(){
  // define an enum instance
  let action = TrafficSignal::Red;
  //print the value of action
  println!("What is the signal value? - {:?}", action);
  //invoke the enum method 'is_stop' and print the value
  println!("Do we have to stop at signal? - {}", action.is_stop());
}

```

Output

```rust
What is the signal value? - Red
Do we have to stop at signal? - true
```

#### Enums and Match Control Flow Operator

The match statement can be used to compare values within an enum. The match statement can be written within a main function or any other user-defined function.

#### Syntax

The match statement can be written within a function be it main or any other user-defined function.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672136460191/aa6d60a2-2138-4469-bed4-876e31312a61.png align="center")

#### Example

The example below makes use of a match statement within a `print_direction` function.

```rust
enum KnightMove{

   Horizontal,Vertical

}

// print function 

fn print_direction(direction:KnightMove) {

   // match statement

   match direction {

      //execute if knight move is horizontal

      KnightMove::Horizontal => {

         println!("Move in horizontal direction");

      },

       //execute if knight move is vertical

      KnightMove::Vertical => {

         println!("Move in vertical direction");

      }

   }

}

fn main() {

   // invoke function `print_direction`

   let knight1 = KnightMove::Horizontal;

   let knight2 = KnightMove::Vertical;

   print_direction(knight1);

   print_direction(knight2);

}
```

output

```rust
Move in horizontal direction
Move in vertical direction
```

#### Enums and Structures

Structures can have an item that is of type `enum`.

* Syntax
    

The following illustration explains the syntax:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672136548521/396317d8-aad9-4bee-b62c-eb508c138c3f.png align="center")

* Example
    

The following example creates an enum `KnightMove` and a `struct` Player.

```rust
// make this `enum` printable with `fmt::Debug`.

#[derive(Debug)]

//define an enum

enum KnightMove{

   Horizontal, Vertical

}

#[derive(Debug)]

// make this `struct` print values of type `enum`  with `fmt::Debug`.

struct Player {

   color:String,

   knight:KnightMove

}

fn main() {

      // instance 1

      let p1 = Player{

      color:String::from("black"),

      knight:KnightMove::Horizontal

   };

      // instance 2

      let p2 = Player{

      color:String::from("white"),

      knight:KnightMove::Vertical

   };

   println!("{:?}", p1);

   println!("{:?}", p2);

}
```

output

```rust
Player { color: "black", knight: Horizontal }
Player { color: "white", knight: Vertical }
```

  
What Is Option?

Option is a built-in enum in the Rust standard library. It has two variants Some and None. 

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672136622717/5c75cbd8-a121-465d-bccd-cd14e202e763.png align="center")

* Variants:
    
    * Some(T), returns Some value T
        
    * None, returns no value
        

#### When to Use Option?

* Options is a good choice when:
    
    * The return value is none
        
        * Rust avoids including nulls in the language, unlike other languages. For instance, the function that returns a value may actually return nothing. So, here the Option variant None comes in handy.
            
    * The value of the variable is optional
        
        * The value of any variable can be set to some value or set to none.
            
    * Out of bound exception is to be displayed
        
        * This is useful in the case of an array, string or a vector when an invalid index number tries to access it.
            

#### Example 1: Return Value Is None

The following example shows that if the else construct has no value then it can simply return None.

```rust
fn main() {

   println!("{:?}", learn_lang("Rust"));

   println!("{:?}", learn_lang("Python"));

}

fn learn_lang(my_lang:&str)-> Option<bool> {

   if my_lang == "Rust" {

      Some(true)

   } else {

      None

   }

}


```

output

```rust
Some(true)
None

```

Note: None does not take a parameter unlike Some.

#### Example 2: Optional Variable Value

The following example makes level variable of the struct Course as Option of type String. That means that it’s optional to set any value to it. It can be set to some value or it can be set to none.

```rust
//declare a struct
struct Course {
   code:i32,
   name:String,
   level: Option<String>, 
}
fn main() {
   //initialize
   let course1 = Course  {
      name:String::from("Rust"),
      level:Some(String::from("beginner")),
      code:130
   };
   let course2 = Course  {
      name:String::from("Javascript"),
      level:None,
      code:122
   };
   //access
   println!("Name:{}, Level:{} ,code: {}", course1.name, course1.level.unwrap_or("Level".to_string()), course1.code);
   println!("Name:{}, Level:{} ,code: {}", course2.name, course2.level.unwrap_or("No level defined!".to_string()), course2.code);
}
```

output

```rust
Name:Rust, Level:beginner ,code: 130
Name:Javascript, Level:No level defined! ,code: 12
```

#### Example 3: Index Out of Bound Exception

The example below uses a match statement that takes an index of string using `match.str.chars().nth(index_no)` and executes the Some block if `index_no` is in range and None block otherwise.

```rust
fn main() {

  // define a variable

  let str = String :: from("Educative");

  // define the index value to be found

  let index = 12;

  lookup(str, index);

}

fn lookup(str: String, index: usize) {

  let matched_index = match str.chars().nth(index){

    // execute if match found print the value at specified index 

     Some(c)=>c.to_string(),

     // execute if value not found

     None=>"No character at given index".to_string()

     };  

  println!("{}", matched_index);

}
```

output

```rust
No character at given index
```

#### `is_some()` , `is_none()` Functions

Rust provides `is_some()` and `is_none()` to identify the return type of variable of type Option, i.e., whether the value of type Option is set to Some or None.

#### Example 1

The following example checks whether the variable value of type Option is set to Some or None.

```rust
fn main() {
    let my_val: Option<&str> = Some("Rust Programming!");
    print(my_val); // invoke the function
   
}
fn print(my_val: Option<&str>){
     if my_val.is_some(){ // check if the value is equal to some value
        println!("my_val is equal to some value");
    }
    else{
        println!("my_val is equal to none");
    }
}

```

output

```rust
my_val is equal to some value
```

We need to do is to ensure that these functions return true or false. That’s where `assert_eq` and `assert_ne` functions come in handy.

* Assert Macros
    
    * `assert_eq!(left, right)` - evaluates to true if left value is equal to that of right
        
    * `assert_ne!(left, right)` - evaluates to true if left value is not equal to that of right
        

#### The output of assert expression?

* If the assertion passes no output is displayed, and if doesn’t the code gives an error saying that the assertion failed
    

#### Example 2

The following example uses the `assert_eq!` macro to check whether the variable value of type Option is set to Some or None.

Note: The assertion passes since the expression evaluates to true.

```rust
fn main() {
    let my_val: Option<&str> = Some("Rust Programming!");
    // pass since my_val is set to some value so left is true, and right is also true
    assert_eq!(my_val.is_some(), true); 
    // pass since my_val is set to some value so left is false, and right is also false
    assert_eq!(my_val.is_none(), false);
}
```

#### Result and Enum

* What Is Result?
    

Result is a built-in enum in the Rust standard library. It has two variants `Ok(T)` and `Err(E)`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672136879859/83af108b-63d7-462b-9f97-2905ad74b1cc.png align="center")

* Variants:
    
    * `Ok(T)`, returns the success statement of type `T`
        
    * `Err`, returns the error statement of type `E`.
        
* When to Use Result?
    
    * Result should be used as a return type for a function that can encounter error situations. Such functions can return an Ok value in case of success or an Err value in case of an error.
        
* Result and Function
    
    * Using Result as a function return type can be used to return various kinds of success and error codes to let the calling function decode the execution state of the called function.
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672136902851/b50f993b-177f-487e-893e-4aa0fefe382c.png align="center")

#### Example 1

The following code has a function `file_found` which takes a number i and returns a Result of type i32, in case of variant Ok and bool, in case of Err.

```rust
fn main() {
   println!("{:?}",file_found(true)); // invoke function by passing true 
   println!("{:?}",file_found(false)); // invoke function by passing false
}
fn file_found(i:bool) -> Result<i32,bool> {
   if i { // if true
      Ok(200) // return Ok(200)
   } else { // if false
      Err(false) // return Err(false)
   }
}

```

output

```rust
Ok(200)
Err(false)
```

Example 2

The following code has a function `divisible_by_3` which takes a number i and returns a Result of type String in case of both variants Ok and Err. If i is `divisible by 3 Ok(Given number is divisible by 3)` is returned and `Err(Given number is not divisible by 3)`.

```rust
fn main() {
   println!("{:?}", divisible_by_3(6)); // invoke function by passing a number 6
   println!("{:?}", divisible_by_3(2)); // invoke function by passing a number 2
}
fn divisible_by_3(i:i32)->Result<String,String> {
   if i % 3 == 0 { // if number mod 3 equals 0
      Ok("Given number is divisible by 3".to_string()) // return this statement
   } else { // if if number mod 3 is not equals 0
      Err("Given number is not divisible by 3".to_string()) // return this statement
   }
}
```

output

```rust
Ok("Given number is divisible by 3")
Err("Given number is not divisible by 3")
```

`is_ok()`, `is_err()` Functions

Rust helps you to check whether the variable of type Result is set to Ok or Err.

```rust
fn main() {
   let check1 = divisible_by_3(6);
   if check1.is_ok(){ // check if the function returns ok
      println!("The number is divisible by 3");
   }
   else{
      println!("The number is not divisible by 3");

   }
   let check2 = divisible_by_3(2);
   if check2.is_err(){ // check if the function returns error
      println!("The number is not divisible by 3");
   }
   else{
      println!("The number is divisible by 3");

   }
}
fn divisible_by_3(i:i32)->Result<String,String> {
   if i % 3 == 0 { // check i modulus 3
      Ok("Given number is divisible by 3".to_string())
   } else {
      Err("Given number is not divisible by 3".to_string())
   }
}
```

output

```rust
The number is divisible by 3
The number is not divisible by 3
```

#### Example 2

The following example uses the assert\_eq! macro to check whether the variable value of type Result is set to Ok or Err.

```rust
fn main() {
   let check1 = divisible_by_3(6);
   assert_eq!(check1.is_ok(), true);  // left is true and right is true so the assertion passes
   let check2 = divisible_by_3(2);
   assert_eq!(check2.is_err(), true); // left is true and right is true so the assertion passes
}
fn divisible_by_3(i:i32)->Result<String,String> {
   if i % 3 == 0 {
      Ok("Given number is divisible by 3".to_string())
   } else {
      Err("Given number is not divisible by 3".to_string())
   }
}
```

Note: The assertion passes since the expression evaluates to true.  

#### Traits

When there are multiple different types behind a single interface, the interface can tell which concrete type to access. This is where the traits come in handy.

* What Are Traits?
    

Traits are used to define a standard set of behaviour for multiple structs.

They are like interfaces in Java.

Suppose you want to calculate the area for different shapes. We know that the area is calculated differently for every shape. The best solution is to make a trait and define an abstract method in it and implement that method within every struct impl construct.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672137164402/de837663-524e-4b70-8b73-9cbb8a101f19.png align="center")

#### Types of Methods in Traits

There can be two types of methods for traits

* Concrete Method
    
    * The method has a body meaning that implementation of the method is done within the method.
        
* Abstract Method
    
    * The method that does not have a body means that implementation of the method is done by each struct in its own `impl` construct.
        

#### Declare a Trait

Traits are written with a trait keyword.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672137611166/b9c35b75-035a-45c7-91e3-db56dd0fedfa.png align="center")

* Naming Convention Name of the trait is written in CamelCase
    

#### Implement a trait

Traits can be implemented for any structure.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672137639869/d50848fc-b46b-4578-8cc2-7ffd2cce7f69.png align="center")

Example

The following example explains the concept of trait:

```rust
fn main(){

   //create an instance of the structure

   let c = Circle  {

      radius : 2.0,

   };

   let r = Rectangle  {

      width : 2.0,

      height : 2.0,

   };

   println!("Area of Circle: {}", c.shape_area());

   println!("Area of Rectangle:{}", r.shape_area());

}

//declare a structure

struct Circle {

   radius : f32,

}

struct Rectangle{

    width : f32,

    height : f32,

}

//declare a trait

trait Area {

   fn shape_area(&self)->f32;

}

//implement the trait

impl Area for Circle {

   fn shape_area(&self)->f32{

      3.13* self.radius *self.radius

   }

}

impl Area for Rectangle {

   fn shape_area(&self)->f32{

      self.width * self.height

   }

}
```

output

```rust
Area of Circle: 12.52
Area of Rectangle:4
```

#### Introduction to Modules

* What Are Modules?
    
    * Modules are a collection of items that can contain structs, functions, enums, vectors, arrays, etc.
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672139511575/2d5e72c9-4109-4ece-9ade-19e02984aa60.png align="center")

💡Why make a module?

* As a result of making modules,
    
    * the program code becomes organized.
        
    * you can use the same name for things like a struct. For example, you can use the name Configuration in different modules and code it differently. Otherwise, you would have different clumsy names for the struct like EngineConfiguration, ConsoleConfiguration etc.
        

#### Declare a Module

To declare a module in Rust use the mod keyword followed by the name of the module and the body of the module within curly braces `{ }`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672139579471/69565494-5fd3-454d-8000-893f507c7f72.png align="center")

* Naming Convention
    
    * Name of the module should be written in snake\_case.
        

#### Invoking a Module

The module can be invoked from anywhere within the program code.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672139610639/86042bcb-7fe8-4bfc-a52b-d0c27991b5fa.png align="center")

#### Keywords for Modules

* The following keywords are used for declaring modules:
    
    * mod - declares a new module
        
    * pub - makes a public module
        
    * use - imports the module in the local scope
        

Note: Modules are declared by the mod keyword and are private by default.

#### Example

The following example makes use of the mod keyword to declare a module named r, and defines a function `print_statement` within the module:

```rust
// declare a module

mod r {

  fn print_statement(){

    println!("Hi, this a function of module r");

  }

}

// main function

fn main() {

  // invoke a module 'r'

   r::print_statement();

}
```

The above code generates an error, ❌, because the function print\_statement is private

#### Controlling Visibility Within the Same File Using 'pub'

The `pub` keyword makes the item public and visible outside its scope.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672139895550/8d334783-5563-449f-ac5a-a5a6163e062a.png align="center")

#### Privacy Rules

The following are two privacy rules when declaring modules:

* Rule No: 1
    

If an item is public it can be accessed from anywhere, i.e., within main function or any other module.

#### Example: Invoke a Public Function Directly

The following example declares a function public `print_statement()` within the mod r:

```rust
// declare a module

mod r {

  pub fn print_statement(){

    println!("Hi, this a function of module r");

  }

}

// main function

fn main() {

  println!("Let's go inside the module");

  // invoke a module 'r'

   r::print_statement();

}
```

output

```rust
Let's go inside the module
Hi, this a function of module r
```

#### Rule No: 2

* If an item is private it can be accessed using its parent module meaning it can be accessed within the module but not outside it.
    
* Example: Invoke a Private Function Indirectly through a Public Function
    
* The example declares a module mod r which has two functions:
    
    * A public function `my_public_function()`
        
    * A private function `my_private_function().`
        

`self` can refer to a function or any item within the same module.

```rust
// declare a module

mod r{

  fn my_private_function(){

    println!("Hi, I'm a private function within the module");

  }

  pub fn my_public_function(){

    //! also works without writing self i.e.

    //! my_private_function();

    println!("Hi,I'm a public function within the module");

    println!("I'll invoke private function within the module");

    self::my_private_function(); 

    

  }

}

// main function

fn main() {

  println!("Let's go inside the module");

  // invoke a module 'r'

   r::my_public_function();

}
```

output

```rust
Let's go inside the module
Hi,I'm a public function within the module
I'll invoke private function within the module
Hi, I'm a private function within the module
```

```rust
If an item is private, it can be called from within the child module.
```

#### Example: Access a Private Function through a Child Module

📝If there is a module within the module, then the outer module is called the parent module and the module inside the parent module is called the child module. This is known as a nested module

The example declares a module mod outer\_module which has:

* A private functionmy\_private\_function().
    
* `inner_module` - Inner module has one public function `my_public_function()`
    

The following example shows how the private function is accessed in the child module using the keyword super followed by `::` and the function name in the parent module.

`super` keyword refers to the parent module.

```rust

// main function
fn main() {
 println!("Let's go inside the module");
 outer_module::inner_module::my_public_function();
}
// declare a module
mod outer_module {
 // function within outer module
 fn my_private_function() {
   println!("Hi, I got into the private function of outer module");
 }
 // declare a nested module
 pub mod inner_module {
   // function within nested module
   pub fn my_public_function() {
     println!("Hi, I got into the public function of inner module");
     println!("I'll invoke private function of outer module");
     super::my_private_function();
   }
 }
}
```

output

```rust
Let's go inside the module
Hi, I got into the public function of inner module
I'll invoke private function of outer module
Hi, I got into the private function of outer module
```

Even though the function `my_private_function()` is declared private, the main() function can invoke it indirectly because the function it calls is public.

#### Example: Access a Root Function

The example below shows how the root function (a function that exists outside the module) can be accessed within the function of a module. Write `super::` followed by the root function name.

`super` can allow accessing a root function from within the module.

```rust

// main function
fn main() {
  println!("Let's go inside the module");
  my_module ::my_public_function();
}
fn my_function(){
  println!("Hi, you came inside the root function using super");
  }

// declare a module
mod my_module {
  // function within outer module
  pub fn my_public_function() {
    println!("Invoke root function");
    super::my_function();
  }
}
```

output

```rust
Let's go inside the module
Invoke root function
Hi, you came inside the root function using super
```

#### Control Visibility Within Different Files Using 'pub'

When modules get large and become cumbersome to store in a single file, it is possible to move their definitions to a separate file to make the code easier to navigate. It is possible to access a module even if it belongs to a different file. To use the module in a different file, write mod followed by the name of the file in which the module is declared.

* Implicit Declaration A block of code put in a file without wrapping in a mod block implicitly declares a module.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140164589/5a6d346d-27a4-449e-8295-cefc39450876.png align="center")
    

* Import the module
    

```rust
mod file_name
```

* Call the module
    

```rust
file_name::x
```

Where `x` can be any construct within the module, i.e., function, array, trait, struct.

📝 Rust code is always put in files with `.rs` extension

#### Explicit Declaration

The code in a file is wrapped within the mod block. This explicitly declares a module.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140127718/61b74467-7df5-437e-beb6-a787e3911476.png align="center")

* Import the module
    

```rust
mod file_name
```

* Call the module
    

```rust
 file_name::module_name::x
```

where x can be any construct within the module, i.e., function, array, trait, struct.

#### Privacy Rule

* If the module belonging to some other file is to be made accessible then it should be made public by using the pub keyword before the mod.
    

📝Once the module is made public using pub, all privacy rules for defining modules within the same file apply.

#### Example

The following example shows how a module in another file can be accessed.

* Implicit declaration The following example declares a module implicitly in a file `my_mod.rs` and calls it from [`main.rs`](http://main.rs). Note: In implicit declaration modules are public by default
    

[main.rs](http://main.rs)

```rust
mod my_mod; 

fn main() {

  println!("Invoke function in my_mod.rs");  

  my_mod::my_public_function();

}
```

my\_mod.rs

```rust
// declare a module
pub fn my_public_function() {
    println!("I am a public function in my_mod.rs");
}
```

output

```rust
Invoke function in my_mod.rs
I am a public function in my_mod.rs
```

#### Explicit declaration

* The following example declares a module in a file `my_mod.rs` and call it from [`main.rs`](http://main.rs).
    

[main.rs](http://main.rs)

```rust
mod my_mod; 

fn main() {

  println!("I am a public function in my_mod.rs");

  my_mod::module::my_public_function();

}
```

my\_mod.rs

```rust
// declare a module
pub mod module{
pub fn my_public_function() {
    println!("I am a public function in my_mod.rs");
}
}
```

output

```rust
I am a public function in my_mod.rs
I am a public function in my_mod.rs
```

#### The 'use' Keyword

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140317561/2421b391-4627-489d-b33d-ac235e29e047.png align="center")

#### Why Use the use Keyword?

The benefit is greatest when items in the same module need to be referred to in the code again and again. Now, we don’t have to type the entire path over and over.

The following example shows how we can write a precise code using a use keyword:

```rust
pub mod chapter {
    pub mod lesson { // mod level 1
        pub mod heading { // mod level 2
            pub fn illustration() {  // mod level 3
              println!("Hi, I'm a 3rd level nested function");
            }
        }
    }
}
use chapter::lesson::heading; // make use of `use` keyword
fn main() {
    heading::illustration(); // call the function
}
```

output

```rust
Hi, I'm a 3rd level nested function
```

#### Glob Operator `( * )`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140495584/859bcf92-de83-4aff-9a5d-6c4766c0e224.png align="center")

The glob operator helps you to prevent writing `EnumName::variant` when assigning `enum` value to a variable.

the following example shows how we can avoid writing a lengthy code using the glob operator `*`.

```rust
// make this `enum` printable with `fmt::Debug`.

#[derive(Debug)]

enum KnightMove{

   Horizontal,Vertical

}

use KnightMove::*; // use of globe operator

fn main() {

   // use enum

   let horizontal_move = Horizontal; // Horizontal is shortcut for KnightMove::Horizontal

   let vertical_move = Vertical; // Vertical is shortcut for KnightMove::Vertical

   // print the enum values

   println!("{:?}", horizontal_move);

   println!("{:?}", vertical_move);

}
```

output

```rust
Horizontal
Vertical
```

#### Memory Management

In many programming languages, there is no need to bother about where the memory is allocated. But in system programming languages like Rust, a program’s behaviour depends upon the memory being used, i.e., stack or heap.

#### Stack

* When the size of data is known at `compile-time`, a stack is used for storage.
    

#### What Is a Stack?

A stack is a Last in First Out(LIFO) data storage memory location meaning all values are stored in a last-in-first-out order. Let’s imagine a real-life analogy to understand stack. There is a huge pile of books with a wall around it. You want the one in the middle. You can’t just slip one from the middle. So, you’ll remove items until the desired location is reached. Inserting values onto the stack is a push operation and removing values from the stack is a pop operation.

* Example All primitive data types that have a fixed size are stored on a stack.
    
* Illustration The following example has a variable a and a variable b. Both are initialized to 1 and stored on the stack.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140753082/9b89d446-8303-46b9-9d18-ebd7bdfbf251.png align="center")

#### Heap

When the size of data is not known at compile time rather it is known at the run time, it goes in a portion of program memory called a heap.

#### What Is a Heap?

Heap is a big data storage and stores values whose size is unknown at compile time. The operating system allocates a space in the heap that is adequate, marks it as in use, and returns a pointer, which is the address of that location.

Let’s imagine a real-life analogy to understand heap. Suppose there are 4 students in a class and the classroom has the accommodations for 8. One new student gets enrolled and is directed to the classroom. Now the total students in the class becomes 5.

* Example Since Vectors and String Objects are resizable, they are stored in a heap.
    
* A String is made up of three parts:
    
    * A pointer to the memory that holds the contents of the string
        
    * Length
        
    * Capacity
        
* This group of the information above is stored on the stack.
    
* The memory on the heap holds the value assigned to the string. Below is the example of string object str which is initialized to Rust.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140662264/204e4986-c1cd-4e66-94cb-731cc5e125a7.png align="center")

Here, ptr is a pointer to the base address of the string str. len is the total length of the string in bytes and capacity is the total amount of memory that the operating system has provided to the string.

#### Stack vs. Heap

\- Pushing values onto the stack is much easier than heap since the operating system does not have to find a big space in memory and mark the pointer for the next allocation.

\- Accessing data from the stack is much faster than heap since the processor will take less time to access the data that is closer to the other data.

#### Ownership

* What Is Ownership?
    
    * Ownership in simple terms means to have possession of something.
        
    * Let’s look at a real-life analogy to explain this concept. If something belongs to you, you say “It’s mine”. 
        
    * Similarly, in Rust, variable bindings can have ownership of what they are bound to.
        

#### Three Rules of Ownership

The following are three rules of ownership:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672140985549/af69d25e-ba39-4f83-a59b-fdadf8c7baaa.png align="center")

#### Rule 1

Each value has a variable binding called its owner.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672141017281/4f965c9f-fa6c-4a1a-8e64-4854055d5696.png align="center")

#### Rule 2

There can only be one owner at a time.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672141088231/f497c634-71e2-438c-8b5f-a61acd96984b.png align="center")

#### Rule 3

* When an owner goes out of scope, it does not remain accessible.
    
    * When the variable goes out of scope, Rust calls function drop automatically at the closing curly bracket (to deallocate the memory). 
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672141111763/5cadb050-20c6-4b1d-be28-916df2ffd275.png align="center")
        

```rust
fn main() {

 let a = 1; // variable a is the owner of the value 1
 let b = 1; // variable b is the owner of the value 1
 let c = 3; // variable c is the owner of the value 3
 println!("a : {}", a);
 println!("b : {}", b);
 println!("c : {}", c);

}// value a, b, c are out of scope outside this block
```

output

```rust
a : 1
b : 1
c : 3
```

* When using the assignment, two situations happen:
    
    * The value gets copied
        
    * The value gets moved
        

##### Copy Type and Moved Type

#### Copy Type

* The ownership state of the original variable (whose value is assigned to another variable) is set to copied state. This means that the value of the assignee variable is copied to the assigned variable. A copy of the value is created so that the assignee variable gets ownership of the value but both variables have their copies.
    
    * Variable assignment in case of primitive data type is a copy type.
        
    * pass by value in a function call is an example of copy type
        

#### Why is a primitive type copied?

* Primitive types are stored on the stack and it’s fast and cheap to copy them.
    

#### Example 1

The following example creates a variable a of type int and assigns the value of a to variable b. Note: The value of a is copied to b

```rust
fn main() {

    let a = 1;

    let b = a; // copy of 'a' is created

    println!("a:{} , b:{}", a, b); // print 'a' and 'b'

}
```

output

```rust

a:1 , b:1
```

#### Example 2

The following example creates a variable an of type array and assigns the value of a to variable b.

```rust
Note: The value of a is copied to b
```

```rust
fn main() {

    let a = [1,2,3];

    let b = a; // copy of 'a' is created 

    println!("a:{:?} , b:{:?}", a, b); // print 'a' and 'b'

}
```

output

```rust

a:[1, 2, 3] , b:[1, 2, 3]
```

##### Moved Type

The ownership state of the original variable (whose value is assigned to another variable) is set to moved.This means that the original variable binding cannot be accessed.

* Variable assignment in case of Non-primitive types such as [String Object](https://rustlabs.kubedaily.com/Beginners/intro-to-strings.html#string-object-string) and Vectors is a moved type.
    

#### Why is non-primitive type moved?

Non-primitive types are stored on the heap. When one variable is assigned to another variable,

two variables will point to the same value. This can’t happen since it violates ownership rule 2 - if one string/vector will

have two owners and one of them changes the value of string there is no way for the other to know. When there is time to clean up the

memory, both will try to find the string to clean it. This would lead to memory corruption. To avoid this, the Rust compiler moves the

owner to the assigned variables and makes the other one inaccessible.

* Example 1
    

The following example creates a variable an of type String and assigns the value of a to variable b. Note: The following code gives an error, ❌, since the value of a is moved to b and a becomes inaccessible.

```rust
fn main() {

   let a = String::from("Rust");

   let b = a; // moves value of 'a' to 'b'

   eprintln!("a:{} , b:{}", a, b); // Error use of moved value 'a'

}
```

* Example 2
    

The following example creates a variable a of type vector and assign the value of a to variable b.

```rust
Note: The following code gives an error, ❌, if the commented statement is uncommented since the value of a is moved to b and a becomes inaccessible
```

```rust
fn main() {

   let a = vec![2, 4, 8];

   let b = a; // move value of 'a' to 'b'

   println!("b : {:?} ", b); // prints 'b'

   //println!("{:?} {:?}", a, b); // Error; use of moved value: 'a'

}   
```

output

```rust
b : [2, 4, 8] 
```

#### The clone Keyword

If you still want both variables to have the same value and be able to use both variables, it is possible to copy the value of one variable to the other using the clone function.

```rust
fn main() {

    let mut a = String::from("Rust"); // define a String and save in 'a'

    let b = a.clone(); // b clones a

    a.push('y');

    println!("a:{} , b:{}", a, b);  // print 'a' and 'b'

}
```

output

```rust
a:Rusty , b:Rust
```

#### Ownership and Functions

the assignment of a variable to another variable will copy or move it. In case of passing variables to the functions, similar can happen.

When a variable whose memory is allocated on heap goes out of scope, the value will be cleaned up by drop unless the data has been moved such that it is now being owned by another variable.

#### Passing Values to a Function

* The ownership of the variable is
    
    * Copied if the value is a primitive data type so the variable can be reused after the function call
        
    * Moved if the value is a non-primitive data type so the value becomes inaccessible after the function call
        

```rust
   fn main() {
    let str = String::from("Rust"); // str comes into scope
                                    // str is a move type

    pass_string_object(str);        // str's value moves into the function...
                                    // ... and becomes in accessible here
    //println!("{}" , str);         // This line will give an error

    let my_int = 10;                // my_int comes into scope

    pass_integer(my_int);          // my_int value is a copy into the function,
                                    // but i32 is a copy type, so can my used
                                    // use my_int if desired

} // Here, my_int and then str goes out of scope

fn pass_string_object(my_string: String) { // my_string comes into scope
    println!("{}", my_string);
} // Here, my_string goes out of scope and `drop` frees the memory

fn pass_integer(my_integer: i32) { // my_integer comes into scope
    println!("{}", my_integer);
} // Here, my_integer goes out of scope

```

output

```rust
Rust
10

```

In this example, value str of type String is moved when passed to the function as an argument and `my_int` of type `i32` is copied.

#### Return Values from a Function

Returning values from a function transfers the ownership to the caller function.

```rust

#[allow(dead_code)]
fn main() {
    
    let str_1 = move_return_value_str_1();  // gives_ownership to str_1                                  
    
    println!("The function gives ownership to string by returning a value \nstring 1 :{}",str_1); // print value of str_1

    let str_2 = String::from("Rust Language");     // assigns a string object to str_2
    
    println!("This is a string declared \nstring 2 :{}",str_2); // print value of str_2   

    let str_3 = moves_str_2_return_str_2(str_2);  // str_2 is moved into the function argument
                                            // return value moves to str_3 
    println!("string 2 passes to the function and returns its value to string 3 \nstring 3 :{}",str_3); // print value of str_3                         
                                     
} // Here, str_3,str_2,str_1 goes out of scope respectively
 // str_3 dropped
 // str_2 moved
 // str_1 dropped
fn move_return_value_str_1() -> String {     // gives ownership 
                                             // value goes to that calls the function
    let my_string = String::from("Rust"); // my_string comes into scope

    my_string                              // my_string is returned 
}

fn moves_str_2_return_str_2(my_string: String) -> String { // my_string comes into 
                                                      // scope
    my_string  // my_string is returned 
}


```

output

```rust
The function gives ownership to string by returning a value 
string 1 :Rust
This is a string declared 
string 2 :Rust Language
string 2 passes to the function and returns its value to string 3 
string 3 :Rust Language

```

Here, in this example, variable `str_1` gains the ownership of a String when the value is returned from the function `move_return_value_str_1`. Variable `str_2` is declared and its value is passed to the function `moves_str_2_return_str_2`. Upon being returned from the function the value is saved in `str_3`.

Note:`str_2` becomes inaccessible since its value is moved in the function

#### Borrowing

* What is Borrowing? Borrowing, in simple terms, means to share. Let’s look at a real-life analogy to explain this concept. You are the owner of a book, but you allow other people to use it.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672142467701/2269d027-8c50-4efa-8f06-1a49434bbe79.png align="center")
    

#### Types of Borrowing

In Rust, borrowing can be of two types:

#### Shared Borrows

The ownership belongs to the assignee variable but the assigned variable can only read the value.

* Multiple variables can borrow the value of the variable at the same time.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672142501790/991958f5-3c55-4bc5-8d38-350e5f7bf9ec.png align="center")

#### Mutable Borrows

The ownership belongs to the assignee variable but the assigned variable can share as well as mutate the value of owner variable.

* Only one variable in the scope can borrow mutably. After the mutable borrow operation, the value of the mutably borrowed variable is moved to become inaccessible.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672142735501/e0488747-59b1-47e4-b3d8-8df90b66ded5.png align="center")

#### Rules of Borrowing

There are two rules to referencing or borrowing variables.

#### Rule 1

There can be either one mutable borrow or any number of immutable borrows within the same scope.

* It is not possible to do a shared borrow as well as a mutable borrow operation simultaneously in the same scope. If you want to do this in the same program code, then enclose a block of code within {}. In the inner block perform the shared borrow, and in the outer block perform the mutable borrow. Vice versa, outer block perform the shared borrow, and in the inner block perform the mutable borrow.
    
* Example #
    

The following example explains rule 1.

```rust
/// cannot mutable borrow b since its already a shared borrow

/// mutable borrow a in outer scope and shared borrow in inner scope

fn main() {
  let mut a = 1; // mutable variable a is defined
  println!("variable `a` :{}", a);
  let b = 1;
  println!("variable `b` :{}", b);
  {
      let r1 = &a; // no problem
      println!("variable `r1` references `a` in inner scope(SHARED BORROW(a)) :{}",r1);
      let r2 = &a; // no problem
      println!("variable `r1` references `a` in inner scope(SHARED BORROW(a) :{}",r2);
      println!("r1:{}\nr2:{}", r1, r2);
     // r1 and r2 scope end here
  }
  let r3 = &mut a; // no problem
  *r3 = 3;
  println!("variable `r1` references `a` in outer scope(MUTABLE BORROW(a) and derefernced it and changed value to 3) :{}",r3);
  let r4 = &b;
  println!("variable `r3` references `b` in outer scope(SHARED BORROW(b)) :{}",r4);

  let r5 = &b;

  println!("variable `r3` references `b` in outer scope(SHARED BORROW(b)) :{}",r5);

  println!("r3:{}\nr4:{}\nr5:{}", r3 , r4 , r5);

}
```

output

```rust
variable `a` :1
variable `b` :1
variable `r1` references `a` in inner scope(SHARED BORROW(a)) :1
variable `r1` references `a` in inner scope(SHARED BORROW(a) :1
r1:1
r2:1
variable `r1` references `a` in outer scope(MUTABLE BORROW(a) and derefernced it and changed value to 3) :3
variable `r3` references `b` in outer scope(SHARED BORROW(b)) :1
variable `r3` references `b` in outer scope(SHARED BORROW(b)) :1
r3:3
r4:1
r5:1
```

#### Rule 2

References must always be valid.

* Cannot reference a value that is moved, i.e., a non-primitive data type.
    
* Example The following example explains rule 2.
    

```rust
fn main() {
  let a = String::from("Rust"); //variable a
  println!("This is a variable a: {}", a);
  let b = a; // moves value of a to b
  println!("Value of variable a is moved to b.\n b : {}", b);
  println!("Now a becomes invalid.Accessing a will give error");
  //let c = &a;

  //println!("This is a variable c trying to access value a: {}", c);

}
```

output

```rust
This is a variable a: Rust
Value of variable a is moved to b.
 b : Rust
Now a becomes invalid.Accessing a will give error
```

#### Functions and Borrowing

Recall pass-by reference in which & mut was used as a function parameter when mutating values inside the function.

* Example
    

The following example declares a function example which takes an owner variable, shared borrow and a mutable borrow as arguments to the function.

```rust
// 'a' an owner variable
// 'b' a shared borrow
// 'c' a mutable borrow
fn example(a: i32, b:& i32,c : &mut i32){
  println!("a: {}, b: {}, c: {}", a , b , c);
   *c=9;
}
fn main(){
   let a = 1;
   let b = 2;
   let mut c = 3;
   example( a, &b , &mut c);
   println!("a: {}, b: {}, c: {}", a , b , c);
}
```

output

```rust
a: 1, b: 2, c: 3
a: 1, b: 2, c: 9
```

#### Borrowing and Slicing

It is possible to borrow a slice of an array, vector or string. Recall the syntax of slicing. It used an & before the name of the variable to be borrowed.

```rust
let arr:[i32;4] = [1, 2, 3, 4]; 
let borrow_a = &arr[0..2];
 
let str=String::from("Rust Programming");
let borrow_str = &str[0..2];
 
let my_vec = vec![1, 2, 3, 4, 5];
let borrow_vec = &my_vec[0..2];
```

Here & indicates a shared borrow.

#### Example

The following examples revise your concept of slicing in arrays, strings, and vectors respectively.

```rust
fn main() {

  let arr:[i32;4] = [1, 2, 3, 4]; // define an array
  let borrow_arr = &arr[0..2]; // slice an array
  println!("arr : {:?}", arr); // print the array
  println!("sliced_arr : {:?}", borrow_arr); // print the sliced array
  let str = String::from("Rust Programming"); // define a String object
  let borrow_str = &str[0..2]; // slice the String object
  println!("str : {:?}", str); // print the String Object 
  println!("sliced_str : {:?}", borrow_str); // print the sliced String
  let my_vec = vec![1, 2, 3, 4, 5]; // define a vector
  let borrow_vec = &my_vec[0..2]; // slice the vector
  println!("vec: {:?}", my_vec);  // print the vector
  println!("sliced_vec : {:?}", borrow_vec); // print the sliced vector

}
```

output

```rust
arr : [1, 2, 3, 4]
sliced_arr : [1, 2]
str : "Rust Programming"
sliced_str : "Ru"
vec: [1, 2, 3, 4, 5]
sliced_vec : [1, 2]
```

#### Lifetimes

* What Is a Lifetime?
    

Lifetimes describes the scope that a reference is valid for. Let’s look at a real-life analogy to explain this concept. You are the owner of a book, but you allow other people to use it for some time.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672142932881/d49b2e93-e1a3-4be3-9521-a9cd382886d7.png align="center")

* Let’s understand this concept in terms of memory management. Having a reference to a resource that someone else has the ownership of can be complicated. For example, imagine this set of operations:
    
    * I have some kind of resource.
        
    * I allow you to borrow the resource.
        
    * I decide my task is completed with the resource, and I want to deallocate it, while you still have the reference of my resource. You still want to use the resource.
        
* Now you are referencing a resource that is deallocated, an invalid resource. This is called a dangling pointer or use after free, when the resource is memory.
    
* To make sure that step four never happens, the concept of a lifetime comes into play!
    

There are two cases to consider.

Case 1: When we know the lifetime of a variable by just looking at the program code

```rust
#![allow(dead_code)] 
struct Course{
   name: String,
   id : i32,
}
fn main(){
  let c1:&Course;
    {
    let c2: Course = Course {
      name : String::from("Rust"),
      id:101,
    };
    }
    c1 = &c2; // allocated reference to a memory location that is dropped
}

```

The above example gives an error, ❌, since c1 references c2 which is deallocated when the scope of c2 finishes.

It is implicit that the scope of c2 finishes and it cannot be used after line 13. But when there is a function that takes an argument by reference, we can be either implicit or explicit about the lifetime of the reference

Case 2: When we can’t say anything about the lifetime of a variable

```rust
#![allow(dead_code)] 

struct Course{

   name: String,

   id : i32,

}

fn get_course(c1: &Course, c2: &Course)->&Course{

  if c1.name == "Rust" {

     c1

  }

  else {

     c2

  }

}

fn main(){

  let c1: Course = Course {

      name : String::from("Rust"),

      id:101,

    };

    

   let c2: Course = Course {

      name : String::from("C++"),

      id:101,

    };

    get_course(c1, c2);   

}


```

The above code gives an error, ❌, which says missing lifetime specifier. In the function definition, c1 is referencing Course and c2 is referencing Course. What if this particular piece of memory is invalid? And for how long does it remains valid? How can we ensure that the function is going to return a valid reference? The compiler is confused what the lifetime of the variable is. Solution: use the lifetime annotation.

#### How does the compiler know the lifetime of a variable?

* The Rust compiler has a borrow checker. It compares the scope of the reference variable and the variable  
    being referred. It ensures that the variable being referred to lives as long as the variable referencing it.
    

#### Lifetime Annotation

* It describes the lifetime of a reference.
    
    * Starts with an apostrophe
        
    * Followed by a small case name, generally a single letter
        

#### Function With Reference Variable Having a Lifetime

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672141862035/445cd50e-4161-4a57-82f7-8cfeace72f06.png align="center")

#### Function With Mutable Reference Variable Having a Lifetime

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1672143012875/09100f1f-b358-4667-8ccc-cf14d448cd81.png align="center")

* Example
    

Now, coming back to the example in Case 2. The following code annotates the lifetime of variable c1, c2, and the return value.

```rust
#![allow(dead_code)] 

struct Course{

   name: String,

   id : i32,

}

fn get_course<'a> (c1: &'a Course, c2: &'a Course) -> &'a Course {

  if c1.name == "Rust" {

     c1

  }

  else {

     c2

  }

}

fn main(){

  let c1: Course = Course {

      name : String::from("Rust"),

      id:101,

    };

   let c2: Course = Course {
      name : String::from("C++"),
      id:101,
    };
    get_course(&c1, &c2);   
}
```

Here, lifetime annotation is used for parameters c1 and c2 meaning both parameters have the same lifetime as that of the function. It is trying to tell the compiler that there is a lifetime for which both of the references are valid and for the same lifetime the reference for the return type is also valid. Earlier the issue was that the time for which the return type was valid was unknown. Now, the borrow checker can check whether the reference is valid or not and gives us a compile-time error if it is invalid. Here, in this case, the reference is valid for \``a`.

The lifetime annotation &lt;'a&gt; is a relationship. It is not used standalone. If you don’t write this, the code will be correct syntactically, but the compiler will generate a compile-time error, ❌.

* How is `a` calculated?
    
    * `a` refers to the lifetime in which all the references are valid, which is the overlap of the related lifetimes, or the common lifetime of n number of instances. As a result, the lifetime having the smallest reference of all references gets assigned to `a`.
        

#### Multiple Lifetimes

There are two possibilities when the reference variables are used as function parameters:

#### Multiple references have the same lifetime

```rust
fn fun_name <'a>(x: & 'a i32 , y: & 'a i32) -> & 'a i32 
  // statements
```

Here, the variable x and y have the same lifetime `a`.

#### Multiple references have different lifetimes

```rust
fn fun_name<'a , 'b>(x: & 'a i32 , y: & 'b i32) 
 // statements  
```

Here, both references x and y have different lifetimes. x has lifetime 'a and y has lifetime 'b.

#### lifetime Elision

* What Is Lifetime Elision?
    

Some common coding patterns were identified and annotating them was an extra effort. In order to avoid that overhead, Rust allows lifetimes to be elided or omitted. This is known as lifetime elision. Rust does so by designing rules for omitting lifetime annotation. They are tested at compile time and are used to determine a lifetime.

* Lifetime Ellison can appear in two ways:
    
    * An input lifetime is a lifetime associated with a parameter of a function.
        
    
    ```rust
     fn fun_name<'a>( x : & 'a i32);  
    ```
    
    Here, the input lifetime of x is 'a.
    
* An output lifetime is a lifetime associated with the return value of a function.
    

```rust
 fn fun_name<'a>() -> & 'a i32;  
```

Here, the output lifetime of return value is 'a.

Note: A function can have both input and output lifetimes.

```rust
Note: A function can have both input and output lifetimes.
```

Here, the x has the input lifetime and the return value has the output lifetime.

#### Rules for Elision

#### Rule 1

Each input parameter gets its own lifetime. If the lifetime is not specified, then the lifetime of each parameter is different.

* Elided lifetime:
    

```rust
fn fun_name( x: &i32, y: &i32){ 
} 
```

* Expanded form:
    

```rust
fn fun_name<'a,'b>( x :& 'a i32, y : & 'b i32){
}
```

#### Rule 2

If there is only one input parameter, its lifetime is assigned to all the elided output lifetimes.

* Elided lifetime:
    

```rust
fn fun_name(x: i32) -> &i32{
}
```

* Expanded form:
    

```rust
fn fun<'a>(x: i32) -> & 'a i32 {
}
```

#### Rule 3

If there are multiple input lifetimes, one of them is `&self` or `&mut self`, the lifetime of self is assigned to all elided output lifetimes.

* Elided lifetime:
    

```rust
fn fun_name(&self, x : &str) -> & str {
}
```

* Expanded form:
    

```rust
fn fun_name<'a,'b>(& 'a self, x : & 'b str) -> & 'a str {
}
```

Note: If the compiler can’t infer the lifetime, it throws an error.
