RUST – Scalar & Compound Types

2023.02.06

SCALAR TYPES

In Rust, the built-in scalar types include integers (such as i32 and u64), floating-point numbers (such as f32 and f64), Booleans (bool), and characters (char). These types can be used to represent single values and are distinct from compound types such as arrays and structs, which can hold multiple values.

INTEGERS

Integers are a basic data type in Rust and can either be signed (able to carry both positive and negative numbers) or unsigned (i.e., can only hold non-negative values). i8, i16, i32, and i64 which stand for 8-bit, 16-bit, 32-bit, and 64-bit signed integers, respectively, are the most often used signed integers. Likewise, u8, u16, u32, and u64, which stand for 8-bit, 16-bit, 32-bit, and 64-bit unsigned integers, respectively, are the most often used unsigned integers. If you don't annotate an integer literal then it defaults to i32 because it's generally the fastest integer even on 64-bit architectures. The isize and usize types, which are signed and unsigned integers with the same size as a pointer on the target platform, are also available in Rust.

FLOATING-POINT

Floating-point numbers are represented by the f32 and f64 types, which represent 32-bit and 64-bit floating-point numbers, respectively. f64 is the default because it has more precision, but this can be really slow on less than 64-bit architectures. These types are based on the IEEE 754 standard for floating-point numbers which requires no special suffix, but you do always need to have at least one digit before the dot.

BOOLEAN

The Boolean data type is represented by the bool keyword. It can have only two values, true and false. The software uses it to make decisions through the use of conditions, loops, and other control structures. The bool type can also be used in logical operators (&&, ||,!), comparison operators (==,!=,, >, =, >=), and other expressions that return a Boolean result.

CHARACTERS

characters are represented by the char type. A character is a single Unicode code point, which can represent a letter, number, symbol, or other type of character.

COMPOUND TYPES

Structs, enums, and tuples are examples of compound types.

Structs are user-defined data types that can contain multiple fields, each with its own data type. They can be used to group related data together.

Enumerations, also known as "enums," are a means to define a list of named constants. Each variant of an enum can have its own fields.

Tuples are fixed-size collections of multiple values of different types. They can be utilised to combine together a few values that have similar meanings.

STRUCTS

In Rust, structures are user-defined data types that can have several fields, each of which has a different data type. They are used to amalgamate related data into a single entity.

A struct can be defined by using the struct keyword, the struct's name, and a pair of curly brackets with the fields inside. A colon separates the name and category of each field.

For example, the following struct defines length and breadth

struct Area {
   length: f64,
   breadth: f64,
}

You can create instances of a struct using the new keyword or by specifying values for each field.

let a = Area { x: 12.0, y: 6.0 };

Structs can also have methods which are attached to a struct and can be called on instances of the struct.

struct Area {
   length: f64,
   breadth: f64,
}

let a = Area { x: 12.0, y: 6.0 };  // initializing

impl Area {
   fn area(&self) -> f64 {
       (self.length * self.breadth)
   }
}

let area = a.area(); // calling area function

ENUM

An enumeration (abbreviated "enum" in Rust) is a data type that can have a certain set of named values, or variants. The enum keyword is used to define enums, which are then followed by the enum's name and a list of variants enclosed in curly braces. Any type of value may be used as the associated value for each version. Here is an illustration of how you would define an enum to stand for the four card suits:

enum Suit {
   Spades,
   Hearts,
   Diamonds,
   Clubs,
}

You can also define an enum with associated values:

enum IpAddr {
   V4(u8, u8, u8, u8),
   V6(String),
}

Enums can also be used in match expressions, which allows you to perform different actions depending on the variant of an enum value.

let some_ip = IpAddr::V4(127, 0, 0, 1);


match some_ip {
   IpAddr::V4(first, second, third, fourth) => println!("{}.{}.{}.{}", first, second, third, fourth),
   IpAddr::V6(address) => println!("{}", address),
}

Match expression enables quick and efficient comparison of a value against a number of patterns. It can be used as an alternative to a string of if-else clauses and frequently improves the readability of code. The "match" keyword is followed by the value to be compared in the basic syntax, and then there are a number of "arms" that each include a pattern and the code that will be run if the value matches the pattern.

TUPLE

Tuple is an ordered group of elements with fixed sizes, where each element may be of a different type. Tuple types are denoted by a comma-separated list of types enclosed in parentheses. For instance, the type of a tuple made up of an integer, a string, and a boolean would be represented by the following (i32, &str, bool).

By encapsulating values of the relevant kinds in parentheses, tuples can be created. For instance, the code that follows produces a tuple with the values 1, "hello," and true:

let my_tuple = (1, "string", true);

Elements of a tuple can be accessed using dot notation and indexing, starting from zero. For example, the following retrieves the second element of the tuple:

let second_element = my_tuple.1;

Additionally, Rust offers a function called "destructuring" that enables you to bind each of a tuple's components to a different variable on a single line.

let (a,b,c) = my_tuple;

Tuple offers easy pattern matching, you can break down values into their component pieces and then bind those parts to variables for additional processing. When working with tuples that have several fields of various types, this can be extremely helpful.

For example, consider the following tuple:

let my_tuple = (1, "string", true);

We can use pattern matching to extract the individual elements of the tuple:

match my_tuple {
    (1, b, c) => println!("{}, {}", b, c),
    _ => println!("not starting with 1"),
}

Here, the first branch matches only the tuples that have the first element equal to 1. The _ in the second branch is a catch-all pattern that matches any value that doesn't match the first branch.

Thank you, Happy learning.