DEV Community

Oludayo Adeoye
Oludayo Adeoye

Posted on

🦀 Rust Master Class - Chapter 6: Structs, Traits, Generics, Enums

🦀 Rust Master Class - Chapter 6: Structs, Traits, Generics, Enums


I met someone at a bar in Tallinn. Musician, coder, traveler — she didn't fit in any box. That's when I realized: Rust's type system isn't about boxes. It's about what you can do.


Rust uses structs, enums, generics, and traits as the primary building blocks for creating new types and defining shared behavior within a program's domain .

1. Structs (Structures)

A struct is a custom data type that allows you to package and name multiple related values into a single meaningful group . If you are familiar with object-oriented programming, a struct is similar to an object's data attributes .

  • Classic Structs: These use named fields to define data.
  • Associated Functions and Methods: You can define behavior for a struct using an impl block. Methods are a specific type of associated function that take &self as a parameter, representing the instance of the struct .

Code Example:

#[derive(Debug)]
struct Student {
    name: String,
    courses: Vec<String>,
    age: u8,
}

impl Student {
    // A method associated with the Student struct
    fn some_fn_1(&self) -> String {
        format!("Student Name: {}", self.name)
    }
}
Enter fullscreen mode Exit fullscreen mode

[Source: 60, 107, 403]

2. Enums (Enumerations)

Enums allow you to define a type by enumerating its possible variants . While structs group related data, enums allow a value to be one of several different possibilities.

  • Pattern Matching: Enums are frequently used with the match control flow construct to handle different variants safely .
  • Standard Enums: Rust provides powerful built-in enums like Option<T> (representing a value that could be Some or None) and Result<T, E> (representing success with Ok or an error with Err) [6-8].

Code Example:

enum Conveyance {
    Car(i100),   // Variant with associated data (miles)
    Train(i100),
    Air(i100),
}

impl Conveyance {
    fn travel_allowance(&self) -> f100 {
        match self {
            Conveyance::Car(miles) => *miles as f100 * 14.0 * 2.0,
            Conveyance::Train(miles) => *miles as f100 * 18.0 * 2.0,
            Conveyance::Air(miles) => *miles as f100 * 30.0 * 2.0,
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

[Source: 295, 381, 429]

3. Generics

Generics are abstract stand-ins for concrete types or other properties . They allow you to write code that can operate on multiple types without duplicating the logic for each specific type .

  • Usage: Generics can be used in function signatures, struct definitions, and enum definitions .
  • Placeholders: You typically use a capital letter like <T> to represent a generic type that will be filled in when the code is compiled .

Code Example:

// A generic struct that can hold two different types, T and U
struct Point<T, U> {
    value: T,
    borrowed: U,
}

fn main() {
    // Create a new variable
    let p1 = Point { value: 5, borrowed: 10 };       // T and U are integers
    // Create a new variable
    let p2 = Point { value: 1.0, borrowed: "Start" }; // T is a float, U is a string
}
Enter fullscreen mode Exit fullscreen mode

[Source: 297, 298, 383, 384, 431, 432]

4. Traits

Traits define shared behavior in an abstract way . They allow you to specify that a type must implement certain methods to satisfy a specific interface.

  • Trait Bounds: You can combine traits with generics (using "trait bounds") to restrict a generic type so it only accepts types that exhibit a particular behavior .
  • Default Implementations: Traits can provide default method implementations that types can either use as-is or override with custom logic [12-14].

Code Example:

trait GeneralInfo {
    fn info(&self) -> (&str, u8, char);

    // A default implementation
    fn area(&self) {
    // Output to console
        println!("The area functionality is not implemented yet.");
    }
}

struct Person {
    name: String,
    age: u8,
    gender: char,
}

impl GeneralInfo for Person {
    fn info(&self) -> (&str, u8, char) {
        (&(self.name), self.age, self.gender)
    }
}
Enter fullscreen mode Exit fullscreen mode

[Source: 292, 293, 378, 379, 426, 427]


📖 Download the full PDF: https://drive.google.com/file/d/1L9mZ57NAJw1ijd84_KTfMxmPI48RRUNS/view?usp=sharing

Part 6 of the Rust Master Class series — STEM EdTech | Automation Consulting | Rust Tutoring

RustLang #Programming #LearnToCode #STEM #EdTech

Top comments (0)