Rust Patterns

cat-rust-patterns

Shared solutions for particular situations specific to programming in Rust.

Basic Patterns

Ownership & Borrowing

PatternDescriptionResources
Ownership & BorrowingOwnership ensure automatic memory clean up when a variable that owns data goes out of scope. This prevents memory leaks. Borrowing allows using a value without taking ownership of it. The borrowing rules prevent data races by ensuring that either multiple parts of the code can read the data, or one part can modify it, but not both at the same time. These are fundamental language features.Rust Book, "Understanding Ownership".
RAII: Resource Acquisition Is InitializationManage resources memory, files, network connections by tying them to the lifetime of an object. Automatic cleanup via Drop trait.Rust Book, "Understanding Ownership".
Interior MutabilityAllow mutation of data even when there are immutable references. Use RefCell, Rc<RefCell<T>>, Cell types.std::cell, std::sync::atomic documentation. The Rust Book, "Interior Mutability".

Error Handling & Customization

PatternDescriptionExample/Resources
Error HandlingRepresent the possibility of failure via Result or absence via Option. Result and Option are part of the prelude. Use match, unwrap, expect, and ? operator. Crates like anyhow and thiserror can help with error management.The Rust Book, "Error Handling".
? OperatorPropagate errors concisely.The Rust Book, "Error Handling".
From TraitDefine conversions between types with From, often used for error handling.Standard library documentation.

Error Handling

Error Customization

RecipeCratesCategories
anyhowanyhowcat-rust-patterns
thisErrorthiserrorcat-rust-patterns
miettemiettecat-rust-patterns
color-eyrecolor-eyrecat-rust-patterns

Generics & Traits

PatternDescriptionExample/Resources
GenericsWrite code that works with multiple types without needing to specify them explicitly.The Rust Book, "Generic Types, Traits, and Lifetimes".
TraitsDefine shared behavior that types can implement.The Rust Book, "Traits".
Trait ObjectsDynamically dispatch to different implementations of a trait at runtime, using Box<dyn Trait> or &dyn Trait.The Rust Book, "Using Trait Objects That Allow for Different Types".
Associated TypesDefine types associated with a trait.The Rust Book, "Associated Types".

Concurrency and Asynchronous Programming

PatternDescriptionExample/Resources
ThreadingFIXMEstd::thread and std::sync provide basic threading and synchronization primitives.
Atomically Reference CountingUse Arc to share data safely between threads. Combine with Mutex or RwLock for mutable access.The Rust Book, "Shared-State Concurrency".
Mutual Exclusion LockUse Mutex for protecting shared data from concurrent access.The Rust Book, "Shared-State Concurrency".
Read-Write LockRwLock allows multiple readers or exclusive writers to access shared data.Standard library documentation.
ChannelsCommunicate between threads using message passing.The Rust Book, "Message Passing Concurrency".
Concurrent Data Structurescrossbeam offers advanced concurrent data structures.
Asynchronous ProgrammingBuild asynchronous applications using e.g. the tokio asynchronous runtime, futures, tasks, and actors.tokio crate documentation.

Functional Programming with Rust

PatternDescriptionExample/Resources
ClosuresUse anonymous functions that can capture their environment. Fundamental language feature.The Rust Book, "Closures".
IteratorsAccess elements of a sequence. Fundamental language feature.The itertools crate provides additional iterator adapters. The Rust Book, "Iterators".

Other

PatternDescriptionExample/Resources
MacrosCode that generates other code at compile time. Fundamental language features.Crates like syn and quote are used for procedural macros. The Rust Book, "Macros".
Unsafe CodeBypass Rust's safety guarantees (use with caution).The Rust Book, "Unsafe Rust". Rustonomicon.
FFI (Foreign Function Interface)Interact with code written in other languages e.g., C.The Rust Book, "Foreign Function Interface".

Design Patterns

Creational Patterns

Design PatternDescriptionHelpful Rust CratesNotes
BuilderConstructing complex objects step-by-step.derive_builder for code generationOften implemented directly using structs and methods. derive_builder reduces boilerplate.
FactoryCreating objects of different types based on some criteria.Often implemented directly using traits, enums, or closures.Traits and generics are frequently used.
Abstract FactoryCreating families of related objects.Often implemented directly using traits and generics
SingletonEnsuring a class has only one instance.Often implemented directly using static variables or lazy initializationCan be implemented with lazy_static though often discouraged in modern Rust.

Builder Patterns

RecipeCratesCategories
bonboncat-rust-patterns
derive_builderderive_buildercat-rust-patterns
typed-buildertyped-buildercat-rust-patterns

Structural Patterns

Design PatternDescriptionHelpful Rust CratesNotes
AdapterMaking incompatible interfaces work together.Often implemented directly using traitsTraits are key for implementing adapters.
CompositeRepresenting hierarchical tree-like structures.Often implemented directly using structs and enums
DecoratorAdding behavior to objects dynamically.Often implemented directly using traitsTraits are commonly used for decorators.
FacadeProviding a simplified interface to a complex system.Usually a matter of structuring your code.
FlyweightSharing objects to reduce memory usage.Often implemented directly using Rc or ArcRc and Arc are used for shared ownership.
ProxyControlling access to another object.Often implemented directlyCan be implemented with custom types and dereferencing.

Behavioral Patterns

Design PatternDescriptionHelpful Rust CratesNotes
Chain of ResponsibilityHandling requests by passing them along a chain of handlers.Often implemented directly using enums or function pointers
CommandEncapsulating a request as an object.Often implemented directly using structs and closuresClosures can be helpful for command implementations.
InterpreterDefining a grammatical representation for a language and providing an interpreter.Parsing crates like nom, pest, lalrpop can be helpful
IteratorProviding a way to access elements of a sequence.Iterators are a core language feature. itertools provides additional iterator adaptors.
MediatorDefining an object that controls how other objects interact.Often implemented directly
MementoCapturing and externalizing an object's internal state.Often implemented directly using structs and serializationserde can be useful for serialization.
ObserverNotifying interested parties when a state changes.event-listenerHelps with implementing the observer pattern.
StateAltering an object's behavior when its internal state changes.Often implemented directly using enums.Enums are often used to represent states.
StrategyChoosing an algorithm at runtime.Often implemented directly using trait objects or enums.Trait objects or enums are commonly used.
Template MethodDefining the skeleton of an algorithm and letting subclasses define specific steps.Often implemented directly using traitsTraits are helpful for defining the template.
VisitorAdding new operations to objects without changing their classes.Often implemented directly using traitsTraits are usually used for visitor implementations.
Dependency InjectionProviding dependencies to components.Dependency injection frameworks (shaku) exist, but it's often handled manually, especially in smaller projects. yew uses dependency injection for its component system.

Code Examples for Rust Design Patterns

RecipeCratesCategories
Implement an Abstract Factorycat-rust-patterns
Clone a Struct Storing a Boxed Trait Object[![dyn-clone][c-dyn-clone-badge]][c-dyn-clone]cat-rust-patterns
pin-project and pin-project-lite[![pin-project][c-pin-project-badge]][c-pin-project][![pin-project-lite][c-pin-project-lite-badge]][c-pin-project-lite]cat-rust-patterns
Implement the Typestate Pattern in Rustcat-rust-patterns
PatternDescriptionExample/Resources
Parsingnom, pest, lalrpopThese crates are useful for parsing various input formats.
Serialization (Serde)serde, serde_json, serde_yml, tomlserde is a powerful framework for serialization and deserialization.
CLI Argument Parsingclap, structoptThese crates help with parsing command-line arguments.
Logginglog, env_logger, tracinglog is a logging facade, and env_logger and tracing are logging implementations.
TestingBuilt-inRust has built-in support for unit and integration testing. Crates like rstest can help with testing.
Asynchronous Programmingtokio, async-std, futurestokio and async-std are asynchronous runtimes. futures provides utilities for working with futures.

References