Automatic Trait Derivation
The derive
⮳ attribute generates code that will implement a trait with its own default implementation on the type you've annotated with the derive syntax.
/// `derive` is a powerful tool in Rust that allows you to automatically /// implement certain traits for your structs and enums. /// /// Here we derive several common traits for a simple struct `S` that wraps an /// `i32`. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Default)] struct S(i32); fn main() { println!("{:?}", S(0)); // Courtesy of `Debug`. println!("{}", S(1) == S(1)); // Courtesy of `PartialEq`, `Eq`. }
You can use the cargo_expand
⮳ utility to see the exact code that is generated for your specific type.
See also:
- Derive⮳.
Derive More
Derive More (crates)⮳ derive lots of additional, commonly used traits and static methods for both structs and enums:
- Arithmetic Traits:
Add
,Sub
,Mul
,Div
,AddAssign
, etc. for custom numeric types. - Conversion Traits:
From
,Into
,TryFrom
,TryInto
for easy type conversions. - Smart Pointer Traits:
Deref
,DerefMut
for implementing container types. Display
andError
: Better formatting and error handling.Constructor
: Auto-generates constructors for structs.- Boolean Operators:
Not
,BitAnd
,BitOr
, etc.
//! The `derive_more` crate extends Rust's built-in derive functionality to
//! provide more automatic implementations for common traits.
//!
//! Add to your `Cargo.toml`:
//! ```toml
//! [dependencies]
//! derive_more = "2.0.1" # Or latest
//! ```
use derive_more::Add;
use derive_more::AddAssign;
use derive_more::Constructor;
use derive_more::Deref;
use derive_more::DerefMut;
use derive_more::Display;
use derive_more::From;
use derive_more::Into;
use derive_more::Sub;
use derive_more::SubAssign;
/// Basic numeric type with arithmetic operations.
#[derive(Add, AddAssign, PartialEq, Debug)]
struct Point {
x: i32,
y: i32,
}
/// Newtype pattern with conversion traits.
#[derive(From, Into, Display, Debug)]
struct UserId(u64);
/// Struct with a constructor.
#[derive(Constructor, Debug)]
struct User {
id: UserId,
name: String,
active: bool,
}
// Using `Deref` and `DerefMut`.
#[derive(Deref, DerefMut, Debug)]
struct Stack<T> {
#[deref]
#[deref_mut]
items: Vec<T>,
}
fn main() {
// Using `Add` and `AddAssign`.
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 3, y: 4 };
let p3 = p1 + p2; // Thanks to `Add`.
assert_eq!(p3, Point { x: 4, y: 6 });
let mut p4 = Point { x: 5, y: 6 };
p4 += Point { x: 1, y: 1 }; // Thanks to `AddAssign`.
assert_eq!(p4, Point { x: 6, y: 7 });
// Using `From` and `Into`.
let user_id = UserId::from(12345);
let raw_id: u64 = user_id.into();
assert_eq!(raw_id, 12345);
// Using `Display`.
println!("User ID: {}", UserId(67890)); // Prints "User ID: 67890".
// Using `Constructor`.
let user = User::new(UserId(12345), "Alice".to_string(), true);
println!("{:?}", user); // User { id: UserId(12345), name: "Alice", active: true }.
// Using `Deref` and `DerefMut`.
let mut stack = Stack {
items: vec![1, 2, 3],
};
stack.push(4); // Using `Vec`'s push method through `DerefMut`.
assert_eq!(stack.len(), 4); // Using `Vec`'s len method through `Deref`.
}
// More complex example: Multiple derives on a single type.
#[derive(
Add, AddAssign, Sub, SubAssign, From, Into, Display, Debug, Clone, Copy,
)]
struct Amount(f64);
// Custom error type with derive_more's `Error` trait.
// `std::error::Error` requires `std::fmt::Debug` and `std::fmt::Display`.
#[derive(Debug, derive_more::Error, Display, From)]
enum AppError {
#[display("Database error")]
DatabaseError,
#[display("Insufficient funds")]
InsufficientFundsError,
}
// Using multiple types with `derive_more`.
fn transfer_amount(
from: &mut Amount,
to: &mut Amount,
value: Amount,
) -> Result<(), AppError> {
if from.0 < value.0 {
return Err(AppError::InsufficientFundsError);
}
*from -= value;
*to += value;
Ok(())
}
Related Topics
- Attributes.
- Rust Patterns.