Rustlings Topic: Structures

Rust has three struct types: a classic C struct, a tuple struct, and a unit struct.

Have a look at Structures & Method Syntax chapter and keyword struct API document to understand Rust’s structure.

You may find solution code for the topic from my repo.

  1. structs1.rs
  2. structs2.rs
  3. structs3.rs

structs1.rs

In this first exercise, we are going to implement classic struct & tuple struct.

/* file: "exercises/structs/structs1.rs" */
struct ColorClassicStruct {
    name: String,
    hex: String,
}

struct ColorTupleStruct<'a>(&'a str, &'a str);

#[derive(Debug)]
struct UnitStruct;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn classic_c_structs() {
        let green = ColorClassicStruct {
            name: "green".to_string(),
            hex: String::from("#00FF00"),
        };

        assert_eq!(green.name, "green");
        assert_eq!(green.hex, "#00FF00");
    }

    #[test]
    fn tuple_structs() {
        let green = ColorTupleStruct("green", "#00FF00");

        assert_eq!(green.0, "green");
        assert_eq!(green.1, "#00FF00");
    }

    #[test]
    fn unit_structs() {
        let unit_struct = UnitStruct;
        let message = format!("{:?}s are fun!", unit_struct);

        assert_eq!(message, "UnitStructs are fun!");
    }
}

structs2.rs

Rust provides update syntax to create instances of struct from the existing object.

/* file: "exercises/structs/structs2.rs" */
#[derive(Debug)]
struct Order {
    name: String,
    year: u32,
    made_by_phone: bool,
    made_by_mobile: bool,
    made_by_email: bool,
    item_number: u32,
    count: u32,
}

fn create_order_template() -> Order {
    Order {
        name: String::from("Bob"),
        year: 2019,
        made_by_phone: false,
        made_by_mobile: false,
        made_by_email: true,
        item_number: 123,
        count: 0,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn your_order() {
        let order_template = create_order_template();
        // Update syntax used.
        let your_order = Order {
            name: "Hacker in Rust".to_string(),
            count: 1,
            ..order_template
        };
        assert_eq!(your_order.name, "Hacker in Rust");
        assert_eq!(your_order.year, order_template.year);
        assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
        assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
        assert_eq!(your_order.made_by_email, order_template.made_by_email);
        assert_eq!(your_order.item_number, order_template.item_number);
        assert_eq!(your_order.count, 1);
    }
}

In case you missed, take a closer look at

#[test]
fn your_order() {
    let order_template = create_order_template();
    // Update syntax used.
    let your_order = Order {
        name: "Hacker in Rust".to_string(),
        count: 1,
        ..order_template
    };
    // ...
}

where ..order_template is used. Any other fields that are not mentioned will be copied from the order_template automatically.

structs3.rs

In Rust, structure definition & implementation are separated. We need impl block to implement method for the structure. Check Method Syntax chapter for the further information.

/* file: "exercises/structs/structs3.rs" */
#[derive(Debug)]
struct Package {
    sender_country: String,
    recipient_country: String,
    weight_in_grams: i32,
}

impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
        if weight_in_grams <= 0 {
            panic!("Negative weight is passed");
        } else {
            Package {
                sender_country,
                recipient_country,
                weight_in_grams,
            }
        }
    }

    fn is_international(&self) -> bool {
        if self.sender_country != self.recipient_country {
            true
        } else {
            false
        }
    }

    fn get_fees(&self, cents_per_gram: i32) -> i32 {
        self.weight_in_grams * cents_per_gram
    }
}

You might notice new macro panic! is used. When panic! is executed, it will terminate the program immediately. It is useful to assert conditions.

Rust provides a lot of macros for the assertion. To list some (but not limited to) common macros…

Continue with Rustlings Solution