我想创建一对 setter/getter 函数,其中名称是基于共享组件自动生成的,但我找不到任何生成新名称的宏规则示例。
有没有办法生成像
fn get_$iden()
和SomeEnum::XX_GET_$enum_iden
这样的代码?
paste
板条箱,它提供了一种在宏中创建串联标识符的稳定方法。
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
板条箱提供了一种稳定的方法来创建适用于任何> = 1.15.0的Rust版本的新标识符。
#[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 });
不,从 Rust 1.22 开始不是。
如果您可以使用夜间构建...
是:
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 } }
如果您需要的只是一个唯一的名称,并且您不在乎它是什么,那么这可能很有用。我用它来解决一个问题,即每次调用宏都需要创建一个唯一的静态来保存单例结构。我无法使用粘贴,因为我没有可以首先粘贴在一起的唯一标识符。