在宏内调用`stringify!`

时间:2019-04-08 22:51:53

标签: rust rust-macros

此宏在调用时进行编译:

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(...)]属性中。

有没有可行的解决方法?

1 个答案:

答案 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
}