DEV Community

Cover image for 🦀 Rust Master Class - Chapter 13: Efficient Programming
Oludayo Adeoye
Oludayo Adeoye

Posted on

🦀 Rust Master Class - Chapter 13: Efficient Programming

🦀 Rust Master Class - Chapter 13: Efficient Programming


My running coach said: 'Stop trying to run faster. Start running smoother.' I was wasting energy fighting my body. Efficient Rust is the same — stop fighting the compiler, start working with it.


Efficient programming in Rust involves leveraging the type system and memory model to ensure safety and performance. Key patterns for managing complex data structures and behavior include structured initialization, appropriate dispatching, and the builder pattern.

1. Initializing Struct Instances

Efficient initialization often relies on the Default trait, which allows a type to provide a sensible default value. This is particularly useful when using the struct update syntax to initialize a few fields while leaving the rest to their defaults .

  • Key Concept: Instead of manually defining every field, you can use ..Default::default() to fill in the remaining fields of a struct .
  • Default for Enums: You can also implement Default for custom enums to specify the starting state .

Code Example:

#[derive(Default)]
struct Customer {
    name: String,
    age: u8,
    membership: Membership,
}

#[derive(Debug)]
enum Membership { New, Loyal }

impl Default for Membership {
    fn default() -> Self { Membership::New }
}

fn main() {
    // Initializing only the 'name' field
    // Create a new variable
    let c1 = Customer {
    // Allocate a new String on the heap
        name: String::from("Alice"),
        ..Default::default() // age and membership take default values
    };
}
Enter fullscreen mode Exit fullscreen mode

2. Static vs. Dynamic Dispatch

Dispatch determines how Rust handles calls to trait methods. The choice between static and dynamic dispatch is a trade-off between compile-time performance and runtime flexibility [3-5].

  • Static Dispatch: Uses trait bounds (e.g., <T: Trait>). The compiler generates a specific version of the function for every concrete type used. This is faster because it allows for inlining but can lead to larger binary sizes (code bloat) .
  • Dynamic Dispatch: Uses trait objects (e.g., &dyn Trait or Box<dyn Trait>). It uses a vtable to look up the method at runtime. This is necessary when you need a collection of different types that all implement the same trait [3-5].

Code Example:

trait Print { fn print(&self); }

// Static Dispatch: Resolved at compile time
fn static_display<T: Print>(value: T) {
    value.print();
}

// Dynamic Dispatch: Resolved at runtime via vtable
fn display_dynamic(value: Vec<Box<dyn Print>>) {
    for i in value {
        i.print();
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Builder Pattern

The Builder Pattern is an efficient way to construct complex objects, especially those with many optional fields. It separates the construction logic from the actual struct representation .

  • Key Concept: You create a secondary "Builder" struct where fields are typically wrapped in Option<T>. Methods are chained to set these values, and a final build() method creates the target object .
  • Benefits: It prevents "telescoping constructors" (where you have many versions of a new function) and makes code more readable .

Code Example:

struct Customer {
    name: String,
    username: Option<String>,
    age: Option<u8>,
}

struct CustomerBuilder {
    name: String,
    username: Option<String>,
    age: Option<u8>,
}

impl CustomerBuilder {
    fn username(&mut self, username: String) -> &mut Self {
        self.username = Some(username);
        self
    }

    fn build(self) -> Customer {
        Customer {
            name: self.name,
            username: self.username,
            age: self.age,
        }
    }
}

fn main() {
    // Create a new variable
    let user = CustomerBuilder {
        name: "the developer".to_string(),
        username: None,
        age: None,
    }
    .username("the developer_developer".to_string()) // Chaining
    .build();
}
Enter fullscreen mode Exit fullscreen mode

[7-9]


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

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

RustLang #Programming #LearnToCode #STEM #EdTech


📚 Practice Resources

GitHub Repository: https://github.com/PacktPublishing/Rust-Programming-Master-Class-from-Beginner-to-Expert

Try it yourself: https://play.rust-lang.org/

Run the code from this chapter in the Rust playground, then clone the repo to continue your Rust journey!


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

RustLang #Programming #LearnToCode #STEM #EdTech

Top comments (0)