Unfortunately am into this rust thing now.. there is no going back, lets learn this mf.

Intro | notes to me#

Rust is a compiled programming language like go | C | C++, to add more in rust memory management is manual unlike go | java | js etcc, where you will get automatic GC on ur runtime. In Rust there is a in house tool called cargo, which is the dependency manager, similar to npm in js, cargo new project creates a new project with directories src/main.rs, cargo.toml files, cargo.toml files contains the project information like project_name, dependencies needed etc.

  • cargo build - builds your program and puts the executable under target/debuge/*.
  • cargo check - builds your program and checks if there are any issues, but it won’t produce any binary/executable so its fast compared to build.
  • cargo run - builds and produce an executable and also runs the executable for us, similar to go run main.go
fn hello_world() {
    println!("Hello World!");
}

fn main() {
    hello_world();
}

Above is the basic Hello world program in rust, as you can see in rust function is declared using fn keyword, one interesting thing i found is instead of normal println here we are calling println!, the ! means we are calling a macro(kinda c macro) not a normal function.

Crate#

Crates in rust are kinda of dependencies/npm packages in binary or library, that we can use in our application, these can be downloaded using cargo(package manager).

Variables and Mutability#

Any Variables that u declare in rust, by default it is immutable, this has lot of advantages.

- Safety, devs will know for sure this variable will not be changed for any reason.
- Easier for compilers to do optimization, since we know the exact size and the reason that its not going to change.
- Also used for concurrency, many threads can easily read the same variable, coz no one can edit it.

with the above advantages, of course we can define mutable variables as well with the keyword mut.

fn main() {
    // let name = "Manikandan";
    // println!("Name => {name}");
    // name = "Manikandan Arjunan"; // this is not possible in rust by default, since it is immutable, we need
    // to add mut in line 2 variable declaration

    let mut name = "Manikandan";

    println!("Name initialize => {name}");
    name = "Manikandan Arjunan"; // this is not possible in rust by default, since it is immutable, we need
    println!("Name after update => {name}");
}

Constants#

Constants are similar to variables but will have immutable by default and cannot be changed. Nthg complex, just same constant that we learned in JS, C, Go etc, mut is not allowed to declare when using constants.

Shadowing#

Shadowing is basically redeclaring the same variable again, something like below, i guess rust has this feature so that devs can feel the immutability without using the mut keyword. not sure this is basically breaking the fundamental point that rust is solving => optimization.


fn main() {
    let age = 12;

    println!("Before shadowing: {age}");
    let age = "Manikandan"; //invalid i know, but this is shadowing, technically
    // i can declare same variable again either with same type or different
    println!("After shadowing: {age}");
}

NOTE:

  • In shadowing we can literally change types as u can see above.
  • However if u declare a variable using mut let mut name = "Manikandan", u can’t change the type of name here.

Datatypes#

Rust is a strongly typed language, meaning the compiler should know the type of any variable, usually rust compiler knows a variable type by its value or the type that is defined(this is needed, when u convert one variable to another etc)

fn main() {
    // explicit typing, since we are converting from one to another.
    let age: u16 = "27".parse().expect("Not a age"); 

    // implicit typing, rust compiler will know the type name on compile time.
    let name = "Manikandan Arjunan";

    println!("{age} {name}");
}

Types of datatypes in rust:

  • Scalar - These are individual types which represent a single value or fixed size value like Integer, Float, Bool, Char

    • Integer - Everyone knows this, Integer is a type which includes only integers(no fractions), it also has signed(+ve and -ve) and unsigned(only +ve), Below are the different integer types that rust has, by default if u do something like let age = 21;, by default rust compiler allocates i32 Rust Integer Types
    • Floating Point - Float is basically fractional/decimal numbers.
    • Boolean - Boolean represents true | false.
        let t = true; // implicit compiler knows the type
        let f: bool = false; // with explicit type annotation.
    
    • Boolean - Boolean represents true | false.
    • Char - char represents a single character which is of 4bytes, unlike 1 byte in c language, this is coz it supports more characters like ascii, emoji, japanese etc..
  • Compound - Compound types are basically a group of values with one specific types, EG: Array, objects etc.

    • Tuple - Tuple type is basically a grouping number of values with variety of types, kinda array but not.
    fn main() {
        let tup1: (i16, char, bool) = (2, 'M', false);
    
        let (x, y, z) = tup1; // kinda destructuring in compare with js world.
    
        println!("{x} {y} {z}");
        println!("{}", tup1.0); // this is also possible
    }
    
    • Array - As we know array type is basically collection of values but with same type(unlike other dynamic language), also in rust array size is fixed by default.
    fn main() {
        let arr: [i16; 5] = [1, 2, 3, 5, 6]; // this is one way of declaring array [i16-> type; 5 ->
        // size]
        let arr = [1, 2, 3, 5, 6]; // this is another way of declaring array, where the size
        // and type are determined by the compiler.
        let arr = [3; 5]; // this is another way of initializing where if u want to repeat a
        // specific number with n times, in this case number 3 for 5times.
    
        println!("{}", arr[0]);
    }
    

Functions#

Functions are similar to everyother programming language, with some minor tweaks, mentioned in the below code

// params as usual specify type, for return type use -> arrow operator
// fn add(x: i16, y: i16) -> i16 {
//     return x + y;
// }


// if u see below i have not included semi colon, this is intentional
// x + y is basically an expression so it returns(similar to () => 1 in js)
// if u include semi colon x + y; this becomes statement, so rust returns default
// value () empty tuple
fn add(x: i16, y: i16) -> i16 {
    x + y
}

// fn is the keyword, main is the default function that rust calls automatically on any file
fn main() {
    add(1, 2);
    println!("Hello, world!");
}