我想创建一个setter/getter函数对,其中的名称基于共享组件自动生成,但是我找不到任何宏规则生成新名称的示例。
是否有一种方法可以生成这样的代码:fn get_$iden()
和SomeEnum::XX_GET_$enum_iden
?
我想创建一个setter/getter函数对,其中的名称基于共享组件自动生成,但是我找不到任何宏规则生成新名称的示例。
是否有一种方法可以生成这样的代码:fn get_$iden()
和SomeEnum::XX_GET_$enum_iden
?
paste
crate,该 crate 提供了一种稳定的宏方式来创建连接的标识符。macro_rules! make_a_struct_and_getters {
($name:ident { $($field:ident),* }) => {
// Define the struct. This expands to:
//
// pub struct S {
// a: String,
// b: String,
// c: String,
// }
pub struct $name {
$(
$field: String,
)*
}
paste::item! {
// An impl block with getters. Stuff in [<...>] is concatenated
// together as one identifier. This expands to:
//
// impl S {
// pub fn get_a(&self) -> &str { &self.a }
// pub fn get_b(&self) -> &str { &self.b }
// pub fn get_c(&self) -> &str { &self.c }
// }
impl $name {
$(
pub fn [<get_ $field>](&self) -> &str {
&self.$field
}
)*
}
}
};
}
make_a_struct_and_getters!(S { a, b, c });
我的mashup
软件包提供了一种稳定的方法来创建新标识符,适用于任何Rust版本>=1.15.0。
#[macro_use]
extern crate mashup;
macro_rules! make_a_struct_and_getters {
($name:ident { $($field:ident),* }) => {
// Define the struct. This expands to:
//
// pub struct S {
// a: String,
// b: String,
// c: String,
// }
pub struct $name {
$(
$field: String,
)*
}
// Use mashup to define a substitution macro `m!` that replaces every
// occurrence of the tokens `"get" $field` in its input with the
// concatenated identifier `get_ $field`.
mashup! {
$(
m["get" $field] = get_ $field;
)*
}
// Invoke the substitution macro to build an impl block with getters.
// This expands to:
//
// impl S {
// pub fn get_a(&self) -> &str { &self.a }
// pub fn get_b(&self) -> &str { &self.b }
// pub fn get_c(&self) -> &str { &self.c }
// }
m! {
impl $name {
$(
pub fn "get" $field(&self) -> &str {
&self.$field
}
)*
}
}
}
}
make_a_struct_and_getters!(S { a, b, c });
concat_idents!(get_, $iden)
等将允许你创建新标识符。fn concat_idents!(get_, $iden)(…) { … }
将无法工作。有一个鲜为人知的箱子gensym,它可以生成唯一的UUID名称,并将它们作为宏的第一个参数传递,在逗号后面:
macro_rules! gen_fn {
($a:ty, $b:ty) => {
gensym::gensym!{ _gen_fn!{ $a, $b } }
};
}
macro_rules! _gen_fn {
($gensym:ident, $a:ty, $b:ty) => {
fn $gensym(a: $a, b: $b) {
unimplemented!()
}
};
}
mod test {
gen_fn!{ u64, u64 }
gen_fn!{ u64, u64 }
}
如果你只需要一个独特的名称,而不在乎它是什么,那是很有用的。我曾经用它来解决一个问题,即每次调用宏时都需要创建一个唯一的静态变量来保存一个单例结构体。由于我一开始没有可粘贴在一起的唯一标识符,所以无法使用paste函数。