1 unstable release
0.1.0 | Apr 4, 2022 |
---|
#10 in #keyword
28KB
497 lines
Rust default and keyword macro
Example
Basic example of using default arguments:
use default_kwargs::{default_args, keyword_args};
default_args! {
fn thing(x: i32, y: i32 = 42) -> (i32, i32) {
(x, y)
}
}
fn main() {
let (r, s) = keyword_args! { thing(42) };
assert_eq!(r, 42);
assert_eq!(s, 42);
let (r, s) = keyword_args! { thing(42, y = 666) };
assert_eq!(r, 42);
assert_eq!(s, 666);
}
Like in the most languages that have this feature, positional argument have to come before any arguments with default value.
Limitations
-
No variadics (
fn foo(a: f64, ...)
) -
Complex patterns don't work, i.e.
Point(x, y): Point = Point(5, 20)
would produce an error. -
You will have to pass defaulted arguments only using keywords. That is, you can't do this:
use default_kwargs::{default_args, keyword_args}; default_args! { fn foo(x: f64 = 3.14) {} } fn main() { keyword_args! { foo(2.71) } // error, do `foo(x = 2.71)` instead. }
-
At least for now, it is required that you use full function path in the
keyword_args
macro. The reason is that we can't get the full path to the args struct from the name of the function. This might change in the future.
How does it work
Basically, the default_args
macro generates a new struct and implements
Default
for it based on function's name.
The example above expands to roughly this:
struct ThingArgs {
y: i32,
}
impl Default for ThingArgs {
fn default() -> Self {
Self { y: 42 }
}
}
fn thing(x: i32, ThingArgs { y }: ThingArgs) -> (i32, i32) {
(x, y)
}
And keyword_args
does the opposite:
fn main() {
let (r, s) = thing(
42,
ThingArgs {
..ThingArgs::default()
},
);
}
Credits
Thank you @dtolnay for an amazing work in parsing and macro ecosystems:
- syn
- quote
- cargo-expand
- and many others!
License
MIT or Apache License, Version 2.0 at your option.
Dependencies
~2.2–9.5MB
~100K SLoC