为什么这个宏调用导致一个未解析的名称?

时间:2016-09-24 17:55:31

标签: macros rust

以下是我正在尝试为我正在处理的RPC库实现的宏的简化版本:

#[macro_export]
macro_rules! msgpack_rpc {
    (
        $(
            rpc $name:ident ( $( $arg:ident : $arg_ty:ty ),* ) -> $ret_ty:ty | $err_ty:ty;
        )+
    ) => (
        pub trait Service {
            $(
                fn $name ( &self, $( $arg : $arg_ty ),* ) -> Result<$ret_ty, $err_ty>;
            )+
        }

        pub struct Server;

        impl Server {
            pub fn listen<S>(handle: &(), address: (), service: S)
                    -> ::std::io::Result<()>
                    where S: Service + Send + Sync + 'static {
                let service = move |msg: &str| {
                    let result = match msg {
                        $(
                            stringify!($name) => {
                                service.$name($( $arg ),*)
                                    .map(String::from)
                                    .map_err(String::from)
                            }
                        ),+,
                        _ => String::from("method not supported".into()),
                    };
                };

                Ok(())
            }
        }
    )
}

msgpack_rpc! {
    rpc echo(arg: i64) -> i64 | ();
}

宏扩展无法使用此错误进行编译:

error: unresolved name `arg` [--explain E0425]
  --> <anon>:40:17
   |>
40 |>     rpc echo(arg: i64) -> i64 | ();
   |>                 ^
<anon>:39:1: 41:2: note: in this expansion of msgpack_rpc! (defined in <anon>)

通过阅读类似的问题,我知道macro_rules有时会在扩展陈述方面遇到问题。但是,我很困惑为什么在这种情况下无法扩展项目。

是否有解决方法来修复扩展?

1 个答案:

答案 0 :(得分:3)

在调用函数的上下文中没有名为arg的变量。这是编译器抱怨的“未解析的arg”。

stringify!($name) => {
    $( let $arg = Default::default(); )*
    service.$name($( $arg ),*)
        .map(String::from)
        .map_err(String::from)
}