duck_trait
is a crate aiming at making duck typing very easy and fast.
Add the crate dependency to your Cargo.toml
.
[dependencies]
duck_trait = { git = "https://github.com/AntoineMurat/duck_trait" }
Let's say that you have two structs Dog
and Duck
sharing some
fields and methods (that have the same name and types).
struct Dog { weight: u32 }
impl Dog {
fn make_noise(&self) { println!("Woof"); }
fn make_static_noise() { println!("Static woof"); }
}
struct Duck { weight: u32 }
impl Duck {
fn make_noise(&self) { println!("Quack"); }
fn make_static_noise() { println!("Static quack"); }
}
You might want to create a function/struct/whatever that can take either a
Dog
or a Duck
. Doing so would require you to define a common trait
that you should then implement for both structs.
Using duck_trait
, this boilerplate is done within a macro.
use duck_trait::duck_trait;
duck_trait!(Animal,
[Dog, Duck],
[weight: u32;],
[fn make_static_noise(); fn make_noise(&self);]
);
fn measure_weight_twice<T: Animal>(animal: &mut T) -> u32 {
*animal.weight_mut() *= 2;
animal.make_noise();
T::make_static_noise();
*animal.weight()
}
fn main() {
let mut duck = Duck { weight: 4 };
let mut dog = Dog { weight: 6 };
assert_eq!(measure_weight_twice(&mut duck), 8);
assert_eq!(measure_weight_twice(&mut dog), 12);
}
The syntax is:
duck_trait!(duck_tait_name,
[struct1, struct2, struct3, etc.],
[field1: field1_type; field2: field2_type; etc.],
[function1; function2; etc.]
);
You can then be generic over duck_tait_name
.
Fields can be accessed using the field()
method and can be modified using
the field_mut()
method. Data can be moved out of struct using
std::mem::replace
.
If you don't plan on using any "static method", you can use the duck trait to manipulate trait objects.
use duck_trait::duck_trait;
duck_trait!(Animal,
[Dog, Duck],
[weight: u32;],
[fn make_noise(&self);]
);
fn measure_weight_twice(animal: &mut dyn Animal) -> u32 {
*animal.weight_mut() *= 2;
animal.make_noise();
*animal.weight()
}
Function parameters should not involve pattern matching as function
parameters are expected to follow the pattern $($arg_name:tt : $($arg_type:tt)*),*
.