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:
structs1.rs
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:
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:
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:
let unit_struct = UnitStruct;
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,
}
}
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:
let your_order = Order {
name: String::from("Hacker in Rust"),
count: 1,
..order_template
};
structs3.rs
// 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.