
# Data Types

## Constants

constants can be delared anywhere, convension to use all caps in const
need const keyword, not always eval at compile time
variables can only be assigned once (needs mut to assign more than once (need to be same type))

```rust
const SECONDS_PER_HOUR: i32 = 60 * 60;
```

## Variables

variables are immutable by default
variables can be inferred but sometimes needs explicit typing
    
```rust
    let foo = 5;
```
need to add mut keyword to enable rewriting, generally avoid unless actually used

```rust
    let mut bar = 6;
```

# SHADOWING

#### Cannot have mutable shadows

allows for reuse of namespace instead of spaces_str and spaces_num
```rust
    let spaces = " _ _ ";
    let spaces = spaces.len();
    // will output 5 instead of " _ _ " beacuse that is how long it is
    // the shadow of spaces (first) wont be printed until the overshadow of spaces goes out of scope
    println!("{spaces}"); // output: 5
```

not allowed shadow
```rust
    let mut spaces = " _ _ ";
    spaces = spaces.len();
```
cannot change type of variable once declared

# Primitive Data Types

## Scalars

### Integers

u is for usigned integers
i is for signed integers

number indicated how many bits it takes in memory
```rust    
    let z: i8;      // takes up 8 bits, can store values from -128 to 127
    let c: i16;     // takes up 16 bits
    let d: i32;     // takes up 32 bits (default for integers)
    let e: i64;     // takes up 64 bits
    let f: i128;    // takes up 128 bits
    let g: isize;   // takes up x bits, depends on the system's architecture/cpu

    let h: u8;      // takes up 8 bits, unsigned version (only positive)
                    // can store values from 0 to 255
```

#### Integer Overflow
will reset to the lowest value ie i8 129 -> -126
```rust 
    let example_over_flow: i8 = 129;
```

behavor only in production mode
dev mode will cause a panic and error out/tell you

### Floats
better to use double point due to modern cpus where there is not much difference in speed

#### Single Point Float
takes up 32 bits
```rust
    let a: f32 = 4.0;
```

#### Double Point Float
takes up 64 bits
```rust
    let b: f64 = 2.01;
```

#### Integers Represented Differently
can represent values in hex, oct, bin or dec
can hover with rust-analyzer extension to see value in dec

##### Dec with Reading Aid
value stored 1000
_ used to make easier to read
```rust
    let i = 1_000;
```

##### Hexidecimal
value stored 255
```rust
    let j = 0xff;
```

##### Octal
value stored 63
```rust
    let k = 0o77; 
```

##### Binary
value stored 13
```rust
    let l = 0b1101;
```

##### Bytes
u8 only
value stored 0x41 or 65
```rust
    let m = b'A';
```

## Numeric Operators / Basic Math
Numbers for reference
```rust
    let x: i16 = 8;
    let y: i16 = 5;
```

### Addition
```rust
    let sum  = x + y; // result: 13
```

### Subtraction
```rust
    let difference = x - y; //result: 3
```

### Multiplication
```rust
    let product: i16;
    product = x * y;
```

### Division
```rust    
    let quotent = 45.1 / 54.2;
    let truncated = x / y; // results in 1 (always rounds down)
```

### Remainder
```rust
    let remainder = x % y;
```

### Booleans
must be explicity typed to true or false
0 or 1 not allowed even with let var: bool
```rust
    let n = false;
    let o = true;
```
&& is and operator

### Char
must use single quotes and not "" otherwise will be inferred as string literal
is stored as Unicode Scalar Value allowing for emoji, japanse char and other languages not supported by ASCII
takes 4 bytes in size or 32 bits
```rust
    let p = 'a';
```

## Compound Types
multiple values into one type

### Tuple
A general way of grouping multiple a number of values into one compound type
types do not need to be the same in every position

```rust
    let tup: (i32, f64, u8) = (500, 6.4, 1);
```
The variable tup has values written to it at initialization but it is not requried, order does not matter
similar to a struct in c

Vaules must be destructed out of a tuple to be accessed inidivually, can use a pattern matching to the tuple

```rust
 let (q, r, s) = tup;
```

This is called destructing becasue it breaks it into 3 parts

Can also be accessed with a .

***INDEX STARTS AT 0***
```rust
    let t = tup.0;  // t = 500
    let u = tup.1;  // u = 6.4
    let v = tup.2;  // v = 1
```

#### A Unit

This is a special value where a tuple has no values
```rust
    let w: () = ();
```
This represents an empty type or an empty return type

Expressions will implicitly return a unit if they dont return anything else

### Array

A collection of multiple values
Must have every value be the same type, cannot mix and match
Arrays must be a fixed length at initialization
useful when you want a set number of values or is static

Values are in [] and seperated by ,

```rust
    let xa = [1, 2, 3, 4, 5, 6];
```

Array located in stack same with above types

If you need your array/list to grow or shrink use a vector
If unsure weather to use an Array or Vector pick a vector

Times where using an array is better
```rust
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
```

Accessing items in an array
```rust
    let ya = xa[0]; //value is 1
```

Initializing an Array
```rust
    let za: [i32; 5];   // allows for 5 32 bit signed integers inside
    let aa = [i8; 6];   // allow for 6 8 bit signed integers inside
```

Invalid Array Elements

```rust
use std::io;
fn main() {
    let a = [1, 2, 3, 4, 5];

    // Input of a number
    println!("Please enter an array index.");
    let mut index = String::new();
    io::stdin()
        .read_line(&mut index)
        .expect("Failed to read line");

    // change into a integer
    let index: usize = index
        .trim()
        .parse()
        .expect("Index entered was not a number");

    // access elemetn in array
    let element = a[index];
    println!("The value of the element at index {index} is: {element}");
}
```
this program would compile with not problems
for example inputting 7 into the program
this would cause a runtime error
the program would output an error because it didnt get to the final line println! before exiting 
it casue the program to exit before attempting to access the invalid space
this is a form of safe memory management that rust name

# Complex Data Type

## String Literal

This is a string literal it is hardcoded into a program
Always immutable
Fast and efficient, stored on the stack, property of being immuatable not of any real value
```rust
    let s: &str = "hello";
```

## String

This is a string that is stored on the heap, this can store data unkown (size, char, etc) to you at compile time
Can be mutable, but must request space on the heap then return that memory to the heap, will be returned as soon as it is no longer valid (it calls the drop method from String) 
not as fast and efficient
Example of a string being created form a string literal
```rust
    let ab:String = String::from("hello");
```

String concatinization example
```rust
    let mut s = String::from("hello");
    s.push_str(", world!"); // push_str() appends a literal to a String
    println!("{s}"); // This will print `hello, world!`
```


# Structures
Custom data type that packages up multiple data types into a meaningful manner and call the collection something
More similar to an object, can define related methods to them

Similar to tuples but have to name and define everything inside a struct, like a dictionary but with set names and order
Dont need to know order just know key
## Defining
Need ``struct`` keywork then name of struct, which should describe the significance of the gropued data
All values are seperated by commas these are called fields
general definition of the type created
```rust

struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,

}
```
## Initiating
To use give a owning var name thne concretely define what each value is
define the key: vaule pairs
dont need to initate in the same order they were defined in

```rust
    let mut user1 = User {
            active: true,
            username: String::from("someusername123"),
            email: String::from("someone@example.com"),
            sign_in_count: 1,
    };
```
to access values from the struct the ``dot``notation is used
note the WHOLE struct must be mutable, rust does not allow for partial mutability
```rust
    // user1 email field now is equal to the string example@mail.com
    user1.email = String::from("example@mail.com");
```
Can build a struct with implicit values input by default

```rust
fn build_user (email: String, username: String) {
    User {
        active: true,
        email: email,
        username: username,
        sign_in_count: 1,
    }
}
```
### Init Field Shorthand
This is useful when the param and the struct definition share the same name.
This reduces the amount of time spent on repeating key:value pairs
```rust
fn build_user(email: String, username: String) -> User {
    User {
        active: true,
        username,
        email,
        sign_in_count: 1,
    }
}
```

Only works beacuse param share same name as field key
this is equivalent to ```username:username or email:email```

### Creating Instances from Other Instances with Struct Update Syntax
Often useful to do so, only need to change 1 value

Slow method
```rust
    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@emial.com"),
        sign_in_count: user.sign_in_count,
    };
```
Using Update syntax ``..`` this can be done a LOT Quicker

```rust
    let user2 = User {
        email: String::from("another@email.com"),
        ..user1
    }
    // user1 no longer completely valid
    // can still use user1.email, .active and .sign_in_count
```

This specifies htat the fields not explicity set should be the same as the given instance
This uses the = assignment operator and therefore a ownership move occurs with the ../update syntax

user1 would still be valid if both of the String types in were given new values

## Tuple Structs

This is also allowed but not key:value pairs
This still holds values in the field

```rust
    struct RGBColour (i32, i32, i32);
    struct Point (i32, i32, i32);

    let black = RGBColour(0, 0, 0);
    let origin = Point(0, 0, 0);
```

## Unit Like Struct

This is similar to a unit ()
This holds no data in itself

Useful for when you need to implement a trait on some type but dont want to store data in the type itself

Delcaration
```rust
struct unit_like_type;

    let using_unit_like_struct = unit_like_type; // instance of unit_like_type
```

No need for () in the delcaration

## Structure Ownership

Want each instance of a struct to own the values inside so that the values inside are always valid unless specified

Can use references but need to take advantage of lifetimes which ensures that the reference is valid whilst the structure is valid

This is valid but compiler will ask for lifetime specifiers
```rust
struct User {
    active: bool,
    username: &str,
    email: &str,
    sign_in_count: u64,
}
```

In short use data times that are owned rather than references

## Adding Increased Functionality of Structs with derived traits

print can do many different types of formatting
Cant print out structs by default because there are so many options
with or without braces, commas, should all fields be shown
This will cause an error
```rust
struct Rectangle {
    length: u32,
    width: u32,
}
    let rect1 = Rectangle {
        length: 8,
        width: 4,
    };
    println!("rect1 contains {}", rect1);
```

{} tell println to use Display by default because there is only one way to show many primitive data types

{var_name:?} this is for the format Debug
{var_name:#?} this is for pretty printing in Debug format, good for larger structs

Debug is also not implemented for the struct and therefore not supported

```rust
#[derive(Debug)]
struct Rectangle {
    length: u32,
    width: u32,
}
    // snip
    println!("rect1 contains {rect1:?}");   // single line print, in debug format, output: rect1 contains Rectangle { length: 8, width: 4 }
    println!("rect1 contains {rect1:#?}");  // pretty print in debug format, output: rect1 contains Rectangle {
                                            // length: 8,
                                            // width: 4,
                                            // }
```

Another way to output pretty debug format by default is dbg! macro
this prints out the file and line number as well of where it was called and returns the ownership of the value
this prints to the stderr output stream
this takes ownership of values compaired to println!
prints to stdout output stream

example of using dbg
```rust
fn main() {
    let scale = 2;
    let rect1 = Rectangle {
        width: dbg!(30 * scale),
        height: 50,
    };
    dbg!(&rect1); // because it takes ownership need to pass in a reference
}
```
output
```
[src/main.rs:10:16] 30 * scale = 60
[src/main.rs:14:5] &rect1 = Rectangle {
    width: 60,
    height: 50,
}
```
## Methods
Fucntions that are more closely related to structs

similar to functions decalred, param and output are all the same

run the code when the method is declared elsewhere

unlike functions they are defined in the context of a struct, an enum or a trait

first parameter is always self, which represents the instance of the struct that is is being called upon
just like python methods

definition
```rust
struct Rectangle {
    length: u32,
    width: u32,
}

// implementation block for Rectangle used to define fn related to the struct
// put in this blcok so that the use case doesnt need to be searched
impl Rectangle {
    // fn moved to here to that it has access to the instance with the self reference
    // fn now closely related to the rect struct
    // first param must be the type self: Self or &self which rust lets you shorthand
    // self can be borrowed, mutably borrowed, or take ownership of self
    // should always borrow unless need to transferownership or mutate the stored var
    // &mut self for mutable version of selfs
    // use self when you want to transform the self into something else
    fn area (&self) -> u32 {
        self.length * self.width
    }

    // this is an example of a mthod with exterior params requried
    fn fit_into (&self, other: &Rectangle) {
        self.length > other.length && self.width > other.width
    }
}
```

useage
```rust
    let rect1 = Rectangle {
        length: 8,
        width: 4,
    }
    println!("The area of the reactangle is {} square units",
    // method syntax to call the area func
    // notice dont need any param in, already has access to self reference
    rect1.area()
    );
```

this provides method syntax and dont have to repeat the structure they effect
one impl can house all the methods for a struct, we can have tthe same method name as field name
just differenitate with the use of () this is for a mthod not the field

this is used in getters where you want read only access to a struct, you can make the field pravate but the method public

## Associated Functions

functions in the impl block are associated with the struct
all functions within tthe impl block is associated functions

not all associated methods have a self reference and therefore arent methods

can be used in constructors or destructors, often constructors are what they are used for

new is often used for constructors, not a protected keyword

example
```rust
impl Rectangle {
    // Self is only allowed within the impl scope, referes to what the scope is for, this determines the return type
    fn square(side: i32) -> Self {
        Self {
            length = side,
            width = side,
        }
    }
}
```
to call these types of functions use the :: operator, this is also used in namespaces

ex
```rust
    let square1 = Rectangle::square(3);
```

you have have multiple impl blocks associated with a struct, is the same as hvaing one monolithic one (better for readibility)
some use cases for multiple impl blocks

# Enums
allows for defining a type determined by its possible variants
can only be one variant at a time

definition
```rust
enum IpAddrKind {
    V4, // possible variant value
    V6, // possible variant value
}
``` 

initiation/storing enum value
```rust
    let six = IpAddrKind::V6;
    let four = IpAddrKind::V4;
```

these need to be namespaced using the :: operator in order to tell the compiler which value you mean

other useage
```rust
fn route (ip_kind: IpAddrKind) {}

    // can be called by using either varaint
    route(IpAddrKind::V4);
    route(IpAddrKind::V6);
```

we only know the kind of addr using the enum, to store the value can be done by using a struct
ex

```rust
struct IpAddr {
    kind: IpAddrKind,
    address: String,
}

    let homeIp = IpAddr {
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };

    let loopback = IpAddr {
        kind: IpAddrKind::V6,
        address: String::from("::1"),
    }
```

now each type of ip addr as an assocatiated value

with just an enum and no struct, where the values are directly attached
this is more concise but communicates the same thing

```rust
enum IpAddr {
    V4(String),
    V6(String),
}

    let homeIp = IpAddr::V4(String::from("127.0.0.1"));

    let loopback = IpAddr::V6(String::from("::1"));
```

enums can have different types from another
ipv4 will always have 4 different values from 0-255
```rust
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

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

    let loopback = IpAddr::V6(String::from("::1"));
```

This encoding and differentiating of Ip adresses is so common that the standard library has an enum named IpAddr, this needs to be brought into scope in order to work

This stores two structs for V4 and V6

like this
```rust
struct Ipv4Addr {
    // --snip--
}

struct Ipv6Addr {
    // --snip--
}

enum IpAddr {
    V4(Ipv4Addr),
    V6(Ipv6Addr),
}
```

can put anything in a enum and enums can have unlimited types assocaited with them

could be nothing, i32, string, tuple for example

can implement behavior in relation to an enum

## The Option Enum and Advantages over Null types

this is a special case where the variants are nothing nas something
this is part of the standard library can can be included

this should be handled so that the compiler can check for handling all types
this then handle the case of what if it is empty

a feature of rust is excluding null references

if you try to use a null value as a not null value you get an error
this is due to null or not null as pervasive and extremely easy to make this kind of error

null is still useful for expressing a value that is not present or not valid for some reason
this is a problem of implementation

rust doesnt have nulls but can be expressed as the enum Option<T>
which is defined by the standard library as

```rust
enum Option<T> {
    None,
    Some(T),
}
```

don't need to explicitly bring into scope but can
can also call it by ``Some`` or ``None``
<T> is the generic type parameter
all of these replace the T generic type in the Option enum

```rust
    let some_number = Some(5); // can be inferred due to the value being stored
    let some_char = Some('e'); // can be inferred due to the value being stored

    let absent_number: Option<i32> = None; // needs generic type specification for the None option
```

all valid T is any type

these are not the same and therefore cannot be added
i8 and Option<i8>

the compiler will always ensure that i8 is a valid value
the complier will not ensure that Option<i8> stores a valid value
will have to check if it has a non-null value in the enum then convert it into a T type from Option<T> type in order to use it

this eliminates the issue of it being assumed that is it a non-null type by being forced to handle the null variant
everywhere where the value isn't a Option<T> can be safely assumed to be a non null type

[documentation for Option T](https://doc.rust-lang.org/std/option/enum.Option.html)

This has lots of useful values attached to it

In general you want code that only runs when you have some T and another code that runs when you have a None value
The match expression is a control flow construct that an handle this, it is suited for enums, it will run different code depending on the enum state/value that it has that code can then be used inside the matching value

# Match and Control Flow

A construct that allows you to compare against a series of patterns then execute code based on which pattern matches

Patterns can be made up of literal values, variable names, wildcards and many other things

The power of matches comes from the expressiveness in patterns and the fact that the compiler handles all possible cases

This is like a coin storer where the coin goes into the hole that fits first
Match does this same concept

Coin Example
This takes in a coin enum and returns the value in cents
```rust
enum Coin {
	Penny,
	Nickel,
	Dime,
	Quarter,
}

fn value_in_cents (coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
```

It is used by first saying match then an expression (like a variable without ;)
This is like a if statement but if needs to evaluate to a Boolean for the condition

Match arms has a pattern then the code to run separated by a => , or a => {}, (optional comma) (for multiline/longer expressions)
If the pattern doesn't match then the next arm is tried until a arm fits (compiler will check that all possibilities are accounted for)

## Patterns that Bind to Values
Arms can bind to parts of values that match the pattern
This can allow us to extract values out of enum variants

example
quarters now have a state in which they were minted in

```rust
#[derive(Debug)] // so we can inspect the state in a minute 
enum UsState { 
    Alabama,
    Alaska, 
    // --snip-- 
} 

enum Coin { 
    Penny, 
    Nickel, 
    Dime, 
    Quarter(UsState), 
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1, 
        Coin::Nickel => 5, 
        Coin::Dime => 10, 
        // state is a bind
        Coin::Quarter(state) => { // the binding for state will be the value UsState::Alaska
            println!("State quarter from {state:?}!"); 
            25 
        }
    }
}
```

if the value to match was
coin::Quarter(UsState::Alaska)
then it would print out State quarter from Alaska
because that is the only pattern that matches 

## Matching with Option T

this can be done

here is an example
where there is a function that adds 1 to a non-null type and returns a null type if it is null
```rust
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None, // the null part
            // i binds to the value inside Option i32
            Some(i) => Some(i + 1), // the non-null part
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
```

this handles both the None case and the not-null case

very common pattern in rust to combine enums and matches then binding to the value inside

very useful for when a range of data types are included

## Matches are Exhaustive
Matches must cover all possibilities
there must be an arm for each pattern that could possibly come into contact with it
if you don't he compiler will give an error

all matches must exist therefore making matches exhaustive by default

## Catch All Patterns and _ Placeholder

for example lets say you have a game where if you roll a 3 you add a fancy hat and if you roll a 7 you remove a fancy hat and all other rolls result in the player moving

it would look something like this
```rust
    let dice_roll = 9;
    match dice_roll {
	    // can do specific numbers as the pattern
        3 => add_fancy_hat(),
        7 => remove_fancy_hat(),
        // this is allowed as a catch all this matches against all patterns not listed
        // should go last in the case that it matches all patterns (including 3 and 7)
        other => move_player(other),
    }

    fn add_fancy_hat() {}
    fn remove_fancy_hat() {}
    fn move_player(num_spaces: u8) {}
```
this uses a variable named other not a keyword
this will match
this catch all of other will satisfy the exhaustive requirements of match
catch all must be last, rust will give a warning if this the wrong order and it will never run

if we want to catch all but not use the value do _
this matches to all values and does not blind to that value
this is like ignoring all other values not found in this arm

if you want nothing to happen from the ignore all then return a unit type from the match

for example the arm _ => () does this, this should not be used in the case of a match trying to return something

# Concise Flow Control with if let

This is a concise way of handling the  case where there is only 1 arm and the rest are ignored using _ 

this would look like 
```rust
    let config_max = Some(3u8); // Option<u8> is the value owned by the variable
    match config_max {
        Some(max) => println!("The maximum is configured to be {max}"),
        _ => (), // annoying boilerplate
    }
```

here is how to remove the boilerplate with a if let
this behaves just like the match above
```rust
    let config_max = Some(3u8);
    if let Some(max) = config_max {
        println!("The maximum is configured to be {max}");
    }
```

if let is separated by an =
the max binds to the value in option u8 then max can be used in the body of the if let

the block doesn't run if the pattern doesn't match exactly
this reduces the amount of typing and boilerplate but you lose the exhaustive nature of match which is enforced

if let is a good refactor to when conciseness is preferred and working module/function is "done"

should be used when only matching against one pattern and only EVER ONE pattern

good to get rid of too verbose code
