此宏在调用时进行编译:
macro_rules! remote_optional {
($remote:ident with=$def:ident $def_str:expr) => {
impl $def {
fn deserialize_option<'de, D>(deserializer: D) -> Result<Option<$remote>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrapper(#[serde(with = $def_str)] $remote);
let v: Option<Wrapper> = Option::deserialize(deserializer)?;
Ok(v.map(|Wrapper(a)| a))
}
}
}
}
这不是:
macro_rules! remote_optional {
($remote:ident with=$def:ident) => {
impl $def {
fn deserialize_option<'de, D>(deserializer: D) -> Result<Option<$remote>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrapper(#[serde(with = stringify!($def))] $remote);
let v: Option<Wrapper> = Option::deserialize(deserializer)?;
Ok(v.map(|Wrapper(a)| a))
}
}
}
}
这是因为stringify!($def)
被未经评估地传递到#[serde(...)]
属性中。
有没有可行的解决方法?
答案 0 :(得分:2)
是否可以将两个参数的宏转发到三个参数的宏,从而扩展def
标识符?
macro_rules! remote_optional {
// The one that doesn't work (two arguments)
// forwards to the one that *does* work, expanding the
// string.
($remote:ident with=$def:ident) => {
remote_optional!($remote, with=$def, stringify!($def));
};
// The macro that *does* work
($remote:ident with=$def:ident $def_str:expr) => {
impl $def {
fn deserialize_option<'de, D>(deserializer: D) -> Result<Option<$remote>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrapper(#[serde(with = $def_str)] $remote);
let v: Option<Wrapper> = Option::deserialize(deserializer)?;
Ok(v.map(|Wrapper(a)| a))
}
}
};
}
我们还可以考虑将三个参数的宏作为实现细节。
少量孤立的概念证明:
macro_rules! my_macro {
($x:expr, $y:expr) => {
my_macro!($x, $y, stringify!($x + $y));
};
($x:expr, $y:expr, $msg:expr) => {
println!("{} + {} = {}", $x, $y, $msg);
};
}
fn main() {
my_macro!(3, 2); // 3 + 2 = 3 + 2
}