有没有办法将多个派生别名为单个派生?
Is there a way to alias multiple derives as a single one?
在使用 newtype 模式时,我经常有冗长的派生:
extern crate derive_more;
use derive_more::*;
#[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
struct Foo(i32);
有没有办法把它缩短成这样:
#[derive(Num)]
struct Foo(i32);
其中 Num
是派生宏?
我发现 this, but it seems like one can't expand macros in attributes. 讨论了如何将属性附加到项目,排除了这一点:
#[proc_macro_derive(Num)]
pub fn num_derive(_: TokenStream) -> TokenStream {
let gen = quote! {
#[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
};
gen.into()
}
正如您所提到的,发出的属性必须附加到一个项目,使得这样的 proc-macro 不可能:
#[proc_macro_derive(Num)]
pub fn num_derive(_: TokenStream) -> TokenStream {
let gen = quote! {
#[derive(Eq, PartialEq, Ord, PartialOrd)]
};
gen.into()
}
proc-macros
还带来了必须在单独的箱子中定义的麻烦,因此生成它们或出于人体工程学原因创建简单的箱子是不值得的。
排除了 proc-macros,我们可以看看 macro_rules
。他们对属性有相同的限制。但是,可以将项目定义包装在 proc-macro 中并为其附加属性:
macro_rules! derive_stuff {
($i:item) => {
#[derive(Eq, PartialEq, Ord, PartialOrd)]
$i
}
}
derive_stuff! { struct Foo(i32); }
鉴于此,我们可以创建一个宏,生成一个像上面这样的宏:
macro_rules! derive_alias {
($name:ident => #[derive($($derive:ident),*)]) => {
macro_rules! $name {
($i:item) => {
#[derive($($derive),*)]
$i
}
}
}
}
derive_alias! {
derive_stuff => #[derive(Eq, PartialEq, Ord, PartialOrd)]
}
derive_stuff! { struct Foo(i32); }
所以我创建了一个板条箱 (derive_alias
) 正是这样做的:
use derive_alias::derive_alias;
use derive_more::*;
derive_alias! {
derive_num => #[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
}
derive_num! { struct Foo(i32); }
在使用 newtype 模式时,我经常有冗长的派生:
extern crate derive_more;
use derive_more::*;
#[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
struct Foo(i32);
有没有办法把它缩短成这样:
#[derive(Num)]
struct Foo(i32);
其中 Num
是派生宏?
我发现 this, but it seems like one can't expand macros in attributes.
#[proc_macro_derive(Num)]
pub fn num_derive(_: TokenStream) -> TokenStream {
let gen = quote! {
#[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
};
gen.into()
}
正如您所提到的,发出的属性必须附加到一个项目,使得这样的 proc-macro 不可能:
#[proc_macro_derive(Num)]
pub fn num_derive(_: TokenStream) -> TokenStream {
let gen = quote! {
#[derive(Eq, PartialEq, Ord, PartialOrd)]
};
gen.into()
}
proc-macros
还带来了必须在单独的箱子中定义的麻烦,因此生成它们或出于人体工程学原因创建简单的箱子是不值得的。
排除了 proc-macros,我们可以看看 macro_rules
。他们对属性有相同的限制。但是,可以将项目定义包装在 proc-macro 中并为其附加属性:
macro_rules! derive_stuff {
($i:item) => {
#[derive(Eq, PartialEq, Ord, PartialOrd)]
$i
}
}
derive_stuff! { struct Foo(i32); }
鉴于此,我们可以创建一个宏,生成一个像上面这样的宏:
macro_rules! derive_alias {
($name:ident => #[derive($($derive:ident),*)]) => {
macro_rules! $name {
($i:item) => {
#[derive($($derive),*)]
$i
}
}
}
}
derive_alias! {
derive_stuff => #[derive(Eq, PartialEq, Ord, PartialOrd)]
}
derive_stuff! { struct Foo(i32); }
所以我创建了一个板条箱 (derive_alias
) 正是这样做的:
use derive_alias::derive_alias;
use derive_more::*;
derive_alias! {
derive_num => #[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
}
derive_num! { struct Foo(i32); }