Rust3 Using Structs to Structure Related Data & Enums and Pattern Matching

Rust study notes

Rust Programming Language Introduction Tutorial Course Notes

Reference textbook: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community)

Lecture 5: Using Structs to Structure Related Data

//define a struct
#[derive(Debug)]
struct User{<!-- -->
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool, // trailing comma is allowed
}

//rectangle struct
#[derive(Debug)]
struct Rectangle{<!-- -->
    width: u32,
    height: u32,
}

impl Rectangle{<!-- -->
    // method to calculate the area of a rectangle
    fn area( & amp;self) -> u32{<!-- -->
        self.width * self.height
    }

    // method to check if a rectangle can hold another rectangle
    fn can_hold( & amp;self, other: & amp;Rectangle) -> bool{<!-- -->
        self.width > other.width & amp; & amp; self.height > other.height
    }

    // associated function
    fn square(size: u32) -> Rectangle{<!-- --> // does not take self as parameter
        Rectangle{<!-- -->
            width: size,
            height: size,
        }
    }
}

fn main() {<!-- -->
    // create an instance of struct
    let mut user = User{<!-- -->
        email: String::from("[email protected]"),
        username: String::from("abc"),
        active: true,
        sign_in_count: 1,
    };

    println!("{},{},{},{}", user.email, user.username, user.active, user.sign_in_count);
    // change the value of the struct
    user.email = String::from("[email protected]");
    

    println!("{}", user.email);

    // create a new instance of struct using function

    let user2 = build_user(String::from("[email protected]"), String::from("user2"));

    // create a new instance of struct using struct update syntax

    let _user3 = User{<!-- -->
        email: String::from("[email protected]"),
        username: String::from("user3"),
        ..user2 // use the remaining fields from user2
    };

    // create a tuple struct
    struct Color(i32, i32, i32);
    let _black = Color(0, 0, 0);

    // create a unit struct
    //struct UnitStruct;// no fields

    //calculate the area of a rectangle
    let rect = Rectangle{<!-- -->
        width: 30,
        height: 50,
    };

    // create a method for the struct
    println!("The area of the rectangle is {} square pixels.", rect.area());
    println!("{:#?}", rect);

    let rect2 = Rectangle{<!-- -->
        width: 10,
        height: 40,
    };

    println!("Can rect hold rect2? {}", rect.can_hold( & amp;rect2));

    // create a square using associated function
    let square = Rectangle::square(3);
    println!("The area of the square is {} square pixels.", square.area());
}


// create a function that returns a struct
fn build_user(email: String, username: String) -> User{<!-- -->
    User{<!-- -->
        email: email,
        username: username,
        active: true,
        sign_in_count: 1,
    }
}

Lecture 6: Enums and Pattern Matching

//create an enum
#[derive(Debug)]
enum IpAddrKind{<!-- -->
    V4,
    V6,
}

//create an enum with data
// enum IpAddrKindWithData{<!-- -->
// V4(u8, u8, u8, u8),
// V6(String),
// }

//four = IpAddrKind::V4(127, 0, 0, 1);

#[derive(Debug)]
struct IpAddr {<!-- -->
    kind: IpAddrKind,
    address: String,
}

#[derive(Debug)]
enum Message{<!-- -->
    Quit,
    Move {<!-- -->x: i32, y: i32},
    Write(String),
    ChangeColor(i32, i32, i32),
}

impl Message{<!-- -->
    fn call( & amp;self){<!-- -->
        //method body would be defined here
        println!("Message: {:?}", self);
    }
}
#[derive(Debug)]
enum Coin{<!-- -->
    Penny,
    Nickel,
    Dime,
    Quarter,
}
#[derive(Debug)]
enum CoinWithData{<!-- -->
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}
#[derive(Debug)]
enum UsState{<!-- -->
    //Alabama,
    Alaska,
    // --snip--
}

fn main() {<!-- -->
    //create an instance of the enum
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;

    //print the enum
    route(four);
    route(six);
    route(IpAddrKind::V4);
    route(IpAddrKind::V6);

    //create an enum with data
    let home = IpAddr {<!-- -->
        kind: IpAddrKind::V4,
        address: String::from("127.0.0.1"),
    };
    println!("home: {:?}", home);
    println!("kind: {:?}", home.kind);
    println!("address: {:?}", home.address);

    let q = Message::Quit;
    let m = Message::Move{<!-- -->x: 1, y: 2};
    let w = Message::Write(String::from("hello"));
    let c = Message::ChangeColor(1, 2, 3);
    q.call();
    m.call();
    w.call();
    c.call();
    //print m.x + m.y
    if let Message::Move{<!-- -->x, y} = m{<!-- -->
        println!("x + y = {}", x + y);
    }

    //option enum
    let some_number = Some(5);
    let some_string = Some("a string");
    let absent_number: Option<i32> = None;
    println!("some_number: {:?}", some_number);
    println!("some_string: {:?}", some_string);
    println!("absent_number: {:?}", absent_number);

    let six = plus_one(some_number);
    let none = plus_one(absent_number);

    println!("six: {:?}", six);
    println!("none: {:?}", none);

    //match
    let coin_1 = Coin::Penny;
    let coin_5 = Coin::Nickel;
    let coin_10 = Coin::Dime;
    let coin_25 = Coin::Quarter;
    println!("coin_1: {:?}", coin_1);
    println!("coin_5: {:?}", coin_5);
    println!("coin_10: {:?}", coin_10);
    println!("coin_25: {:?}", coin_25);

    let datacoin_1 = CoinWithData::Penny;
    let datacon_5 = CoinWithData::Nickel;
    let datacoin_10 = CoinWithData::Dime;
    let datacoin_25 = CoinWithData::Quarter(UsState::Alaska);

    println!("datacoin_1: {:?}", datacoin_1);
    println!("datacon_5: {:?}", datacon_5);
    println!("datacoin_10: {:?}", datacoin_10);
    println!("datacoin_25: {:?}", datacoin_25);

    value_in_cents(coin_1);
    value_in_cents_binding_value(datacoin_25);
    
    let v = Some(7u8);
    match v {<!-- -->
        Some(1) => println!("one"),
        Some(3) => println!("three"),
        Some(5) => println!("five"),
        Some(7) => println!("seven"),
        _ => println!("anything"),//default
    };

    //if let
    if let Some(3) = v {<!-- -->
        println!("three");
    }else{<!-- -->
        println!("anything");
    }

    
}

fn route(ip_kind: IpAddrKind) {<!-- -->
    println!("ip_kind: {:?}", ip_kind);
}

fn value_in_cents(coin: Coin) -> u32{<!-- -->
    match coin{<!-- -->
        Coin::Penny => {<!-- -->
            println!("Lucky penny!");
            1
        },
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

fn value_in_cents_binding_value(coin: CoinWithData) -> u32{<!-- -->
    match coin{<!-- -->
        CoinWithData::Penny => {<!-- -->
            println!("Lucky penny!");
            1
        },
        CoinWithData::Nickel => 5,
        CoinWithData::Dime => 10,
        //Coin::Quarter => 25,
        CoinWithData::Quarter(state) => {<!-- -->
            println!("State quarter from {:?}!", state);
            25
        },
    }
}

fn plus_one(x: Option<i32>) -> Option<i32>{<!-- -->
    match x{<!-- --> //match is exhaustive
        None => None,
        Some(i) => Some(i + 1),
    }
}