Skip to main content
A struct (structure) is a user-defined compound data type that aggregates multiple values of potentially different types into a single, cohesive unit. It establishes a custom type signature and memory layout that can be utilized throughout a Rust program.

Struct Variants

Rust provides three distinct structural forms, each with specific syntactic rules and memory characteristics.

1. Named-Field Structs

The standard struct defines explicit identifiers and types for each field.

2. Tuple Structs

Tuple structs rely on positional indexing rather than named fields. They are defined with a type identifier followed by a parenthesized list of component types. To instantiate a tuple struct, you call it like a function. Its fields are accessed using dot notation with zero-based indices.

3. Unit-Like Structs

Unit-like structs contain no fields and consume zero bytes of memory at runtime. They are typically utilized as marker types or to implement traits on a stateless type.

Generics and Lifetimes

Structs can be parameterized with generic types and lifetimes to operate on diverse data types and borrowed data. Generics: Type parameters are declared in angle brackets <T> immediately following the struct identifier.
Lifetimes: If a struct holds a reference, Rust’s borrow checker requires explicit lifetime annotations. This is a fundamental rule guaranteeing that the struct instance cannot outlive the data it references. The lifetime parameter (e.g., 'a) is declared in angle brackets and applied to the reference type.
Multiple generic types and lifetimes can be combined within the same struct definition.

Visibility

By default, structs and their fields are private to the module in which they are defined. To expose a struct or its fields to external modules, the pub visibility modifier must be explicitly applied. A public struct can still encapsulate private fields.

Instantiation and Mutability

Struct instances are created by specifying the struct identifier and providing values for all defined fields. Standard mutability in Rust is inherited from the variable binding. Individual fields cannot be marked as mutable; the entire instance must be declared with mut to allow field modification.
Interior Mutability: Rust provides an exception to inherited mutability through the concept of interior mutability. By wrapping field types in wrapper types or synchronization primitives like Cell, RefCell, or Mutex, you can mutate specific fields even if the struct instance itself is bound immutably.

Initialization Shorthands

Rust provides syntactic sugar to streamline struct initialization. Field Init Shorthand: If a local variable shares the exact identifier as a struct field, the explicit assignment can be omitted.
Struct Update Syntax: The .. operator allows a new struct instance to inherit the values of remaining fields from an existing instance of the exact same type.
Note: Struct update syntax moves data. If the copied fields contain types that do not implement the Copy trait, the original instance will be partially moved and invalidated for those specific fields.

Destructuring and Pattern Matching

Destructuring is the idiomatic method for extracting and binding struct fields to local variables. This is achieved using pattern matching. The .. syntax can be used to ignore remaining fields.

Implementation Blocks (impl)

Behavior is attached to structs using impl blocks. These blocks encapsulate functions associated with the struct’s type.

Memory Layout

By default, Rust does not guarantee the memory layout or field ordering of a struct. The compiler (rustc) is permitted to reorder fields to minimize padding and optimize memory alignment. To enforce a deterministic memory layout, such as strict C-compatibility for FFI (Foreign Function Interface), the #[repr(C)] attribute must be applied to the struct definition.
Tired of Poor Rust Skills? Fix That With Deep Grasping!Learn More