Structs Exercises

Overview

These exercises cover Rust’s three struct types and implementing methods.


structs1 - Three Types of Structs

Concept: Regular, tuple, and unit structs

Regular Struct (named fields)

struct ColorRegularStruct {
    red: u8,
    green: u8,
    blue: u8,
}
 
let green = ColorRegularStruct {
    red: 0,
    green: 255,
    blue: 0,
};
assert_eq!(green.green, 255);  // Access with .field_name

Tuple Struct (positional fields)

struct ColorTupleStruct(u8, u8, u8);
 
let green = ColorTupleStruct(0, 255, 0);
assert_eq!(green.1, 255);  // Access with .0, .1, .2

Unit Struct (no fields)

#[derive(Debug)]
struct UnitStruct;
 
let unit_struct = UnitStruct;
let message = format!("{unit_struct:?}s are fun!");

When to use each:

TypeUse Case
RegularClear, self-documenting fields
TupleSimple wrappers, 2-3 related values
UnitMarkers, traits without data

structs2 - Struct Update Syntax

Concept: Creating structs from existing ones

let order_template = create_order_template();
 
let your_order = Order {
    name: String::from("Hacker in Rust"),
    count: 1,
    ..order_template  // Fill remaining fields from template
};

Key Takeaways:

  • ..other_struct copies remaining fields from another instance
  • Specified fields override the template
  • This is called “struct update syntax”

⚠️ Ownership note: If the template has non-Copy fields (like String), they are moved, not copied.


structs3 - Methods with impl

Concept: Implementing methods on structs

struct Package {
    sender_country: String,
    recipient_country: String,
    weight_in_grams: u32,
}
 
impl Package {
    // Associated function (no self) — called with ::
    fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
        if weight_in_grams < 10 {
            panic!("Can't ship a package with weight below 10 grams");
        }
        Self { sender_country, recipient_country, weight_in_grams }
    }
 
    // Method (takes &self) — called with .
    fn is_international(&self) -> bool {
        self.sender_country != self.recipient_country
    }
 
    fn get_fees(&self, cents_per_gram: u32) -> u32 {
        self.weight_in_grams * cents_per_gram
    }
}

Key Takeaways:

First ParameterCall SyntaxExample
NoneType::function()Package::new(...)
&selfinstance.method()pkg.is_international()
&mut selfinstance.method()pkg.set_weight(...)
selfinstance.method()Consumes the instance
  • Self is an alias for the struct type
  • Field shorthand: sender_country instead of sender_country: sender_country

Rust Book Reference