# Structs

* **Struct**:
  * Structs are user-defined types that allow you to group related data together similar to tuples.
  * Unlike with tuples, in a struct you’ll name each piece of data so it’s clear what the values mean.
  * Adding these names means that structs are more flexible than tuples so you don’t have to rely on the order of the data to specify or access the values of an instance.
  * Structs can have associated methods, which are functions tied to the struct.
  * Have ***struct update syntax*** capabilities using `..`.
  * Types of struct in Rust are:
    * **Regular Struct**: Fields are explicitly named.
    * **Tuple Struct**: Fields are identified by their position (like a tuple).
    * **Unit-Like Struct**: A struct with no field.
* **Method**:
  * Methods are similar to functions: we declare them with the fn keyword and a name.
  * Unlike functions, methods are defined within the context of a struct (or an enum or a trait object)
  * Their first parameter is always self, which represents the instance of the struct the method is being called on.
* References:
  * [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
  * [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)

## structs1.rs

```rust
struct ColorRegularStruct {
    // Add the fields that the test `regular_structs` expects.
    // What types should the fields have? What are the minimum and maximum values for RGB colors?
    red: i32,
    green: i32,
    blue: i32,
}

struct ColorTupleStruct(i32, i32, i32);

#[derive(Debug)]
struct UnitStruct;

fn main() {
    // You can optionally experiment here.
}

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

    #[test]
    fn regular_structs() {
        // Instantiate a regular struct.
        let green = ColorRegularStruct {
            red: 0,
            green: 255,
            blue: 0,
        };

        assert_eq!(green.red, 0);
        assert_eq!(green.green, 255);
        assert_eq!(green.blue, 0);
    }

    #[test]
    fn tuple_structs() {
        // Instantiate a tuple struct.
        let green = ColorTupleStruct(0, 255, 0);

        assert_eq!(green.0, 0);
        assert_eq!(green.1, 255);
        assert_eq!(green.2, 0);
    }

    #[test]
    fn unit_structs() {
        // Instantiate a unit struct.
        let unit_struct = UnitStruct;
        let message = format!("{unit_struct:?}s are fun!");

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

* In this exercise we will define 3 types of struct.
* First is regular struct.
  * Based on the test, it expect 3 fields `red`, `green`, and `blue` so we can define it like this:

    ```rust
    struct ColorRegularStruct {
      red: i32,
      green: i32,
      blue: i32,
    }
    // and use it like this
    let green = ColorRegularStruct {
      red: 0,
      green: 255,
      blue: 0,
    };
    ```
* Second is tuple struct.
  * Based on the test, it also expect 3 fields, so we define it like this:

    ```rust
    struct ColorTupleStruct(i32, i32, i32);
    // and use it like this
    let green = ColorTupleStruct(0, 255, 0);
    ```
* And last is unit-like struct.
  * It's already defined and we just need to instantiate it like this:

    ```rust
    let unit_struct = UnitStruct;
    ```

## structs2.rs

```rust
#[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,
    }
}

fn main() {
    // You can optionally experiment here.
}

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

    #[test]
    fn your_order() {
        let order_template = create_order_template();

        // Create your own order using the update syntax and template above!
        let your_order = Order {
            name: String::from("Hacker in Rust"),
            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 this exercise we need to create an `Order` from `order_template` by using ***struct update syntax***.
* So based on test we only need change `name` and `count` so we do it like this:

  ```rust
  let your_order = Order {
    name: String::from("Hacker in Rust"),
    count: 1,
    ..order_template
  };
  ```
* You can read more about it here: [Creating Instances from Other Instances with Struct Update Syntax](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax).

## structs3.rs

```rust
// Structs contain data, but can also have logic. In this exercise, we have
// defined the `Package` struct, and we want to test some logic attached to it.

#[derive(Debug)]
struct Package {
    sender_country: String,
    recipient_country: String,
    weight_in_grams: u32,
}

impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
        if weight_in_grams < 10 {
            // This isn't how you should handle errors in Rust, but we will
            // learn about error handling later.
            panic!("Can't ship a package with weight below 10 grams");
        }

        Self {
            sender_country,
            recipient_country,
            weight_in_grams,
        }
    }

    // Add the correct return type to the function signature.
    fn is_international(&self) -> bool {
        self.sender_country != self.recipient_country
    }

    // Add the correct return type to the function signature.
    fn get_fees(&self, cents_per_gram: u32) -> u32 {
        self.weight_in_grams * cents_per_gram
    }
}

fn main() {
    // You can optionally experiment here.
}

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

    #[test]
    #[should_panic]
    fn fail_creating_weightless_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Austria");

        Package::new(sender_country, recipient_country, 5);
    }

    #[test]
    fn create_international_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Russia");

        let package = Package::new(sender_country, recipient_country, 1200);

        assert!(package.is_international());
    }

    #[test]
    fn create_local_package() {
        let sender_country = String::from("Canada");
        let recipient_country = sender_country.clone();

        let package = Package::new(sender_country, recipient_country, 1200);

        assert!(!package.is_international());
    }

    #[test]
    fn calculate_transport_fees() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Spain");

        let cents_per_gram = 3;

        let package = Package::new(sender_country, recipient_country, 1500);

        assert_eq!(package.get_fees(cents_per_gram), 4500);
        assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
    }
}
```

* In this exercise we need to fix two method.
* First is `is_international`, based on the test if `sender_country` and `recipient_country` is different the it considered as international, and expected return type is `bool`.

  ```rust
  fn is_international(&self) -> bool {
    self.sender_country != self.recipient_country
  }
  ```
* Second is `get_fees`, based on the test the formula of fees is `weight_in_grams * cents_per_gram` and expected return type is `u32`.

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/rust/rustlings_exercise/07_structs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
