On this page
Structs and Traits
There are three kinds of structs (named fields, tuples, and units). A trait is Rust’s answer to "interfaces"—defining a set of method signatures that any type can implement. The derive macro automatically generates common traits (Clone/Debug/Serialize) for structs, while the orphan rule restricts "who can implement whose trait," preventing dependency conflicts.
Structs: More Than Just "Collections of Data"
// named fields — the most common
; // tuple struct — anonymous fields, suitable for simple wrappers
; // unit struct — ZST, used as a marker type
Tuple structs are suitable for "newtype wrappers"—wrapping an underlying type with a single-field struct to give it new type semantics and prevent misuse:
; // Not f64 — it's Meters!
;
let m = Meters;
let f = Feet;
// let sum = m.0 + f.0; // You can do this, but semantically you shouldn't compare directly
// The compiler won't stop you, but the type system helps distinguish "this is meters" from "that is feet"
Traits: Contracts for Behavior
A trait defines "a set of method signatures"—any type implementing that trait must provide these methods:
Traits are similar to interfaces in Java/C#, but with an important distinction: you can implement your own traits for external types (but you cannot implement external traits for external types—the orphan rule).
Derive: Compiler-Generated Code
derive requires that all fields also implement the corresponding trait. For example, #[derive(Clone)] requires every field to be Clone. The compiler checks these constraints and then generates templated impls—no macros or code generation tools needed.
Orphan Rule: Why You Can't Just impl Anything
// Your crate: my_lib
// OK: MyType is yours
// OK: MyTrait is yours
// OK: The parameter MyType of Vec is yours
// impl Display for String { ... } // ERROR: Display(std) + String(std)
// Both are defined in other crates → orphan rule prohibits this
This rule prevents two crates from providing conflicting impls for the same (type, trait) combination. If this were allowed, the compiler wouldn't know which one to choose, and the coherence check during the linking phase would fail. This is the core guarantee of Rust's modular trait system.
Trait Bounds: Constraining Generics
// Single bound — syntactic sugar
// Equivalent generic syntax
// Multiple bounds
// Where clause — more readable for complex bounds
References
- Rust Book: Chapter 5 (struct), Chapter 10.2 (trait)
- Rust Reference: Traits, orphan rules, derive
Keywords: struct, trait, impl, derive, orphan rule, coherence, trait bound, where clause