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.
// On structs #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Default)] struct S(i32); fn main() { println!("{:?}", S(0)); println!("{}", S(1) == S(1)); }
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.
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;
// The `derive_more` crate extends Rust's built-in derive functionality to
// provide more automatic implementations for common traits.
// Add to your `Cargo.toml`:
// [dependencies]
// derive_more = "2.0.1" # Or latest
// 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 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.