2016-09-24 40 views
1

這裏是一個宏觀的,我想實現一個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有時會擴大陳述的問題。不過,我很困惑,爲什麼它在這種情況下擴大項目有困難。

是否有解決方法來解決擴展問題?

+0

您是否試過將'Service'和'Server'名稱作爲宏參數提供? –

+0

不,我希望宏只聲明內聯項,並希望用戶在需要命名空間的情況下在模塊內擴展。 – euclio

+0

請注意,在這種情況下創建[MCVE]非常有用;這是所有優秀程序員都應具備的技能。這裏是[這種情況下一個潛在的MCVE](http://play.integer32.com/?gist=79165c85749c3707b1149a5bd12862ec)。一旦你製作了一個MCVE,問題通常會變得更加明顯。 – Shepmaster

回答

2

您在調用函數的上下文中沒有任何名爲arg的變量。這是編譯器正在抱怨的「未解決arg」。

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