# Primitive data types

* **bool**

  true or false

```rust
let x = true;
let y: bool = false;

// ⭐️ no TRUE, FALSE, 1, 0
```

* **char**

  A single Unicode scalar value

```rust
let x = 'x';
let y = '😎';

// ⭐️ no "x", only single quotes
//because of Unicode support, char is not a single byte, but four.
```

* **i8, i16, i32, i64**

  Fixed size(bit) signed(+/-) integer types

| DATA TYPE | MIN                  | MAX                 |
| --------- | -------------------- | ------------------- |
| i8        | -128                 | 127                 |
| i16       | -32768               | 32767               |
| i32       | -2147483648          | 2147483647          |
| i64       | -9223372036854775808 | 9223372036854775807 |

💡 Min and max values are based on IEEE standard for Binary Floating-Point Arithmetic; From **-2ⁿ⁻¹ to 2ⁿ⁻¹-1** . You can use **min\_value()** and **max\_value()** to find min and max of each integer type, ex. i8::min\_value();

* **u8, u16, u32, u64**

  Fixed size(bit) unsigned(+) integer types

| DATA TYPE | MIN | MAX                  |
| --------- | --- | -------------------- |
| u8        | 0   | 255                  |
| u16       | 0   | 65535                |
| u32       | 0   | 4294967295           |
| u64       | 0   | 18446744073709551615 |

💡 Same as signed numbers, min and max values are based on IEEE standard for Binary Floating-Point Arithmetic; From **0 to 2ⁿ-1** . Same way you can use **min\_value()** and **max\_value()** to find min and max of each integer type, ex. u8::max\_value();

* **isize**

  Variable sized signed(+/-) integer

Simply this is the data type to cover all signed integer types but memory allocates according to the size of a pointer. Min and max values are similar to i64 .

* **usize**

  Variable sized unsigned(+) integer

Simply this is the data type to cover all unsigned integer types but memory allocates according to the size of a pointer. Min and max values are similar to u64.

* **f32**

  32-bit floating point

Similar to float in other languages, **Single precision**.

💡 Should avoid using this unless you need to reduce memory consumption badly or if you are doing low-level optimization, when targeted hardware not supports for double-precision or when single-precision is faster than double-precision on it.

* **f64**

  64-bit floating point

Similar to double in other languages, **Double precision**.

* **arrays**

  Fixed size list of elements of same data type

```rust
let a = [1, 2, 3]; // a[0] = 1, a[1] = 2, a[2] = 3
let mut b = [1, 2, 3];

let c: [i32; 0] = []; //[Type; NO of elements] -> [] /empty array
let d: [i32; 3] = [1, 2, 3];

let e = ["my value"; 3]; //["my value", "my value", "my value"];

println!("{:?}", a); //[1, 2, 3]
println!("{:#?}", a);
//  [
//      1,
//      2,
//      3
//  ]
```

⭐️ Arrays are **immutable** by default and also **even with mut, its element count can not be changed**.

> 🔎 If you are looking for a dynamic/growable array, you can use **Vec**. Vectors can contain any type of elements but all elements must be in the same data type.

* **tuples**

  Fixed size ordered list of elements of different(or same) data types

```rust
let a = (1, 1.5, true, 'a', "Hello, world!");
// a.0 = 1, a.1 = 1.5, a.2 = true, a.3 = 'a', a.4 = "Hello, world!"

let b: (i32, f64) = (1, 1.5);

let (c, d) = b; // c = 1, d = 1.5
let (e, _, _, _, f) = a; //e = 1, f = "Hello, world!", _ indicates not interested of that item

let g = (0,); //single-element tuple

let h = (b, (2, 4), 5); //((1, 1.5), (2, 4), 5)

println!("{:?}", a); //(1, 1.5, true, 'a', "Hello, world!")
```

⭐️ Tuples are also **immutable** by default and **even with mut, its element count can not be changed. Also if you want to change an element’s value, new value should have the same data type of previous value**.

* **slice**

  Dynamically-sized reference to another data structure

Think you want to get/pass a part of an array or any other data structure. Instead of copy it to another array (or same data structure), Rust allows to create a view/reference to access only that part of data. And it can be mutable or not.

```rust
let a: [i32; 4] = [1, 2, 3, 4];//Parent Array

let b: &[i32] = &a; //Slicing whole array
let c = &a[0..4]; // From 0th position to 4th(excluding)
let d = &a[..]; //Slicing whole array

let e = &a[1..3]; //[2, 3]
let f = &a[1..]; //[2, 3, 4]
let g = &a[..3]; //[1, 2, 3]
```

* **str**

  Unsized UTF-8 sequence of Unicode string slices

```rust
let a = "Hello, world."; //a: &'static str
let b: &str = "こんにちは, 世界!";
```

⭐️ It's an **immutable/statically allocated slice** holding an **unknown sized sequence of UTF-8** code points stored in somewhere in memory. **\&str** is used to borrow and assign the whole array to the given variable binding.

> 🔎 A [String](https://doc.rust-lang.org/std/string/struct.String.html) is a **heap**-allocated string. This string is growable, and is also guaranteed to be UTF-8. They are commonly created by converting from a string slice using the **to\_string()** or **String::from()** methods. ex: `“Hello”.to_string();` `String::from("Hello");`

💡 In general, you should use **String** when you need **ownership**, and **\&str** when you just need to **borrow a string**.

* **functions**

  As we discussed on functions section, b is a function pointer, to plus\_one function

```rust
fn plus_one(a: i32) -> i32 {
    a + 1
}

let b: fn(i32) -> i32 = plus_one;
let c = b(5); //6
```
