Rust Tuples and Arrays - Understanding the use of Primitive Compound Data Types in Rust Programming Language

With practical and easy examples for beginners

Compound types helps in grouping multiple values into a single type. In Rust programming language tuples and arrays are two primitive compound types that are available to us. In this article we will be looking through these two types in a practical aspect.

The Tuple Type

Tuples can be considered as fixed length collections of heterogeneous values i.e. different types of values. We can say that a tuple is a way to group together values of different types to form one compound type.Tuples in Rust are immutable, once declared we cannot be grow or shrink them in size. As by definition Tuples allows to store different types of values this does not mean that we cannot store homogeneous values, Tuples can also be used to make a collection of homogeneous values.

One practical use of Tuple is to store the latitude and longitude of your home, as a tuple will always have a predefined number of values in this specific case we have two.

When we should go for Tuple Type

There is a use case in our application when we don't want our data to be changed, so if we are going to create a data type which will not be going to change through out the application, then we should use tuple type. For example, day of week, month names, etc. Let us see an example for better understanding.

let tup = ('r', 21); tup.0; // 'r' tup.1; // 21

We can also specifically annotate types with the data in tuples for that we have to do this

let tup: (char, i32) = ('r', 21); tup.0; // 'r' tup.1; // 21

Destructing a tuple Consider the following code, this code first creates a tuple with name tup, and in the second line creates a pattern using let keyword to break the tuple into three separate variables a, b and c. The method of breaking a tuple into separate parts in Rust is known as destructing.

fn main() { let tup = (10, 2.8, 15);

let (a, b, c) = tup;

println!("The value of b is: {}", b);

}

We can also destruct a tuple in individual fields during an assignment. Destructing is very useful when we know that a function will be returning a tuple and we want it to separate at the time of function call. The following example shows this :

let mut v = [1, 2, 3, 4, 5, 6];

let (a, b) = v.split_at_mut(3);

// a =[1,2,3] b= [4,5,6]

Also when we are destructing a tuple we can throw away part of it by using a _ . In the example below the first part will be thrown away and only the last will be stored.

let mut v = [1, 2, 3, 4, 5, 6];

let (_, last) = v.split_at_mut(3);

println!("{:?} " , last); // last= [4,5,6]

How to access tuple elements

Tuple elements can be accessed using a dot (.) followed by index of the element we want to access.For example :

fn main() { let tup: (f64, u8) = (16.24, 11);

let value1 = tup.0;

let value2 = tup.1;

}

Unit Type and Value

A type in Rust programming with a zero-sized value, also known as Zero tuple type.The tuple defined without any values, (), is special tuple and has only one value and is written as (). This special type is called as unit type and its value is called the unit value. Expressions implicitly return the unit value if they don’t return any other value.

Everything in a Rust program is an expression, and the an expression that returns nothing returns a (). The Rust compiler will throw an error if we are not returning () in a function without a return type. Unit type can be considered as void in other languages. For example

fn myFun() {
    25i32 // Gives error: mismatched types: expected `()` but found `int`
}

So when you don't care what type of value you are dealing with it is userful, means you can write generic code without worrying about the type of value you are dealing with.

The Array type

Array is another way to create a linear collection in Rust. It is different from a Tuple as arrays cannot be heterogeneous means every element of an array must be of same type (homogeneous). We can say that arrays are collection of homogeneous elements stored linearly. To create an array in Rust we can do this:

fn main() {
    let arr = [1, 2, 3, 4, 5];
}

When to use array

Arrays are useful when we want memory to be allocated on the stack instead of heap, in other words when we are sure that we will always have a fixed number of elements.In short arrays are useful when we know the number of elements will never need to modify. Using arrays for names of the week days in our program is a great example, in this case we would probably use an array because we know it will always contain fixed (7) elements:

let dayOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

Creating arrays in Rust

We can create an array type using square brackets having the type of elements, a semicolon, and total number of elements in the array:

Syntax :

let variable_name:[dataType;size] = [value1,value2,value3....];

let arr: [i32; 5] = [1, 2, 3, 4, 5];

Here i32 is the type of each element of array and 5 is number of elements.

We can also initialize an array to have same value for each element, as shown below:

let arr = [12; 4];

The array named arr will contain 4 elements all set to the value 12. This is same as creating an array like this :

let arr = [12, 12, 12, 12];

The following code will give an error because size of array cannot be variable and must be known at compile time.

fn main() {
   let arr_size: usize = 10;

   let arr = [0; arr_size]; //Error: 

   print!("{}",arr[10])
}

To solve this error modify the code as below:

fn main() {
   const arr_size: usize = 10;

   let arr = [0; arr_size]; //Works because arr_size is const

   print!("{}",arr[10])
}

Accessing Array Elements

Since an array is a linear collection of memory with fixed size allocated on the stack. We can access each element using its index

fn main() {
    let arr = [1, 2, 3, 4, 5];

    let first_element = arr[0];

    let second_element = arr[1];
}

When we access an element using indexing method, Rust checks for the index we have specified is less than length of array. If the index is greater than or equal to the length, Rust will throw index out of bound error at runtime. This is an example when Rust performs memory safety principles.

Accessing array with loop

The following code iterates through elements of an array and corresponding values.

fn main(){
   let arr:[i32;5] = [1,2,3,4,5];

   println!("Size of array is :{}",arr.len());

   for i in 0..4 {
      println!("value of element is : {}",arr[i]);
   }
}

Fetching array using the iter() function

The iter() function is used to fetch values of elements in an array.

fn main(){

let arr:[i32;5] = [1,2,3,4,5];

   println!("Size of array is :{}",arr.len());

   for val in arr.iter(){
      println!("value of element is :{}",val);
   }
}

I've tried to get the most out of tuples and arrays in Rust programming. I hope this article will enrich your path to learning Rust programming.Thank you for considering reading this article.