Use todo! macro for unimplemented traits

todo! macro will compile and run successsfuly the unimplemented traits. But if we call the unimplemented trait it will panic and give error.

Struct

struct Language{
    name: String,
    stable_version: f32,
    launched_year: u32
}

Struct implementation with unimplmented method named – represent

impl Description for Language{    
    fn represent(&self) -> String{     // Error    
    }
}

Main Block


fn main() {
 
   let pro_langauge_rust = Language{
        name: String::from("Rust"),
        stable_version: 1.84,
        launched_year: 2012
    };

    println!("{}" , pro_langauge_rust.name);   
}

Compiler Error-

18 |     fn represent(&self) -> String{
   |        ---------           ^^^^^^ expected `String`, found `()`

Change the Struct implementation with todo! macro

impl Description for Language{    
    fn represent(&self) -> String{   
        todo!();     
        //format!("the language {} was lauched in {} year and current stable version is {}", self.name, self.launched_year, self.stable_version)
    }
}

Output

Rust

todo!() is actually the same as another macro: unimplemented!(). Programmers were using unimplemented!() a lot but it was long to type, so they created todo!() which is shorter.

  • No dummy variable needed
  • Visual “not complete” indicator
  • Will panic if reached

Panic if reached – if we call the unimplemented trait it will panic and give error.

fn main() {
 
   let pro_langauge_rust = Language{
        name: String::from("Rust"),
        stable_version: 1.84,
        launched_year: 2012
    };

    println!("{} {}" , pro_langauge_rust.name, pro_langauge_rust.represent()); // Error
   
}

Output

thread 'main' panicked at src\main.rs:19:9:
not yet implemented

Reference – https://dhghomon.github.io/easy_rust/Chapter_44.html

Unreachable! macro

This macro is kind of like todo!() except it’s for code that you will never do. Maybe you have a match in an enum that you know will never choose one of the arms, so the code can never be reached. If that’s so, you can write unreachable!() so the compiler knows that it can ignore that part.

enum

enum PaymentStatus{
    Succeeded,
    Processing,
    Fail    
}

Enum implementation

impl PaymentStatus {
    fn after_payment_action(&self) -> &str{
        match *self {
            PaymentStatus::Succeeded => "UpdateERP",
            PaymentStatus::Processing => "Wait",
            PaymentStatus::Fail => "Block",
            _ => unreachable!()
        }
    }    
}

unreachable!() is also nice for you to read because it reminds you that some part of the code is unreachable. You have to be sure that the code is actually unreachable though. If the compiler ever calls unreachable!(), the program will panic.

dbg! macro

dbg! is a very useful macro that prints quick information. It is a good alternative to println! because it is faster to type and gives more information

As per the Rust documentation, the dbg! macro works exactly the same in release builds. This is useful when debugging issues that only occur in release builds or when debugging in release mode is significantly faster.

fn main() {
 
   let pro_langauge_rust = Language{
        name: String::from("Rust"),
        stable_version: 1.84,
        launched_year: 2012
    };

    dbg!(&pro_langauge_rust);
    dbg!(pro_langauge_rust.represent());   
}

Output

[src\main.rs:33:5] &pro_langauge_rust = Language {
    name: "Rust",
    stable_version: 1.84,
    launched_year: 2012,
}
[src\main.rs:34:5] pro_langauge_rust.represent() = "the language Rust was lauched in 2012 year and current stable version is 1.84"

env! and option_env! macro

Any sensitive information that are harcoded can be a security breach. To avoid this these should be go set as environment variables. For this use env! or option_env!

env!(“key”) or option_env!(“key”)

env! will panic if the key does not exists. It is better to use env! if you want program to crash when the environment variable is not found.

option_env! – on the other hand is safer as it won’t panic if the key not found, instead allows to handle the error.

let language_name = env!("name");

This will not compile if the environment variable is not set in project. To do this you can use dotenc crate to read variables from .env file.

But what when the variables are set through command line. This won’t even compile to run the project. Use option_env! macro

let language_name = option_env!("name").expect("Language name is required!");

Make Struct Field optional using Option Enum

Use Option to make the struct field optional and set it to None if it has to be empty or Some if the value has to be set.

struct Language{
    name: String,
    stable_version: f32,
    launched_year: u32,
    description: Option<String>
}
{
   let pro_langauge_rust = Language{
        name:  String::from("Rust"),
        stable_version: 1.84,
        launched_year: 2012,
        description: None
    };

    dbg!(&pro_langauge_rust);

    let pro_langauge_rust1 = Language{
        name:  String::from("Rust"),
        stable_version: 1.84,
        launched_year: 2012,
        description: Some("Rust is a compiled language".to_string())
    };

    dbg!(&pro_langauge_rust1);
}

Output

[src\main.rs:37:5] &pro_langauge_rust = Language {
    name: "Rust",
    stable_version: 1.84,
    launched_year: 2012,
    description: None,
}
[src\main.rs:47:5] &pro_langauge_rust1 = Language {
    name: "Rust",
    stable_version: 1.84,
    launched_year: 2012,
    description: Some(
        "Rust is a compiled language",
    ),
}

Check if the option is None or Some using is_none() and is_some() method.

Match patterns

To match patterns use .. or | (pipe) operators. .. is used to match the range while | is used to match multiple OR expressions.

fn get_degree_class(percentage: u32) ->  String{
    match percentage {
        70..=100 => "First-Class Honours".to_string(),
        60..=69 => "Upper Second-Class Degree".to_string(),
        50..=59 => "Lower Second-Class Degree".to_string(),
        40..=49 => "Third Class Degree".to_string(),
        _ => "Fail".to_string()
    }
}

{
    dbg!(get_degree_class(75),get_degree_class(45), get_degree_class(61));
}

Output

[src\main.rs:52:5] get_degree_class(75) = "First-Class Honours"
[src\main.rs:52:5] get_degree_class(45) = "Third Class Degree"
[src\main.rs:52:5] get_degree_class(61) = "Upper Second-Class Degree"

Likewise use ! operator to match the mutiple OR expressions

fn get_degree_class(percentage: u32) ->  String{
    match percentage {
        99 | 100 => "Distinction".to_string(), // This is example. There is nothing above First Class
        70..=98 => "First-Class Honours".to_string(),
        60..=69 => "Upper Second-Class Degree".to_string(),
        50..=59 => "Lower Second-Class Degree".to_string(),
        40..=49 => "Third Class Degree".to_string(),
        _ => "Fail".to_string()
    }
}

Output

[src\main.rs:52:5] get_degree_class(99) = "Distinction"
[src\main.rs:52:5] get_degree_class(45) = "Third Class Degree"
[src\main.rs:52:5] get_degree_class(75) = "First-Class Honours"

For performance user release profile

Release profile – runs fast but compiles slow as it executes all of the compile optimisations.

cargom run --release

fold() method

fold is a consuming iterator adaptor which applies a function to each element of the iteration, accumulating the result into a new value.

This method is used a lot to add together the items in an iterator, but you can also do a lot more. It is somewhat similar to .for_each(). In .fold(), you first add a starting value (if you are adding items together, then 0), then a comma, then the closure. The closure gives you two items: the total so far, and the next item. First here is a simple example showing .fold() to add items together.

{ 
    let some_numbers = vec![9, 6, 9, 10, 11];
    
    println!("Total using fold method - {}", some_numbers
            .iter()
            .fold(0, |total_so_far, next_number| total_so_far + next_number)
        );
}    

Output

Total using fold method - 45

Rust Docs

Check installed components –

rustup component list --installed   

Add Rust docs component

rustup component add rust-docs

Open the Rust book

rustup docs --book
rustup docs std 
rustup docs std::iter

Installing the RUST-

Browse https://rustup.rs/

This should detect the current OS and provide the various installation instructions.

If using Visual Code – use rust-analyzer extension. https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer

Tags- #todo! #macro #rust #unimplemented #traits #dbg! #env!

Loading