2015-06-19 29 views
5

我正尝试使用我在独立模块中创建的宏。参照this SO question,我已经导入了一个宏罚款。但是看来我有为什么我必须在客户端库中公开宏实现的'use'?

更新添加宏实现

lib.rs

#![macro_use] 
use std::fmt; 
use std::ffi::CString; 
use std::ffi::CStr; 
use std::str; 
extern crate libc; 

pub enum DbaxError { 
    DBAXException(String) 
} 

#[macro_export] 
macro_rules! dbax_call_test { 
    ($func : expr) => { 
     { 
      let call_c_func = unsafe { dbax_function(CString::new($func).unwrap().as_ptr(),0) }; 
      match unsafe { getErrorCode() as i32 } { 
       0 => Ok("Done".to_owned() + $func), 
       _ => Err(DbaxError::DBAXException(str::from_utf8(unsafe { CStr::from_ptr(getError()) }.to_bytes()).unwrap().to_string())) 
      } 
     } 

    } 
} 

和main.rs在一个单独的箱子

// Import macro 
#[macro_use] extern crate rustdbax; 
// Import implementation details of macro 
use rustdbax::*; 
use std::ffi::CString; 
use std::ffi::CStr; 
use std::str; 

fn main() { 
    // Call my macro 
    dbax_call_test!("DateAdd"); 
} 

这工作得很好,但use std::*行都是lib.rs中实现的一部分。

为什么我必须在客户端库中公开实现的'use'?作为扩展的一部分,不应该生锈,包括lib.rs中的任何内容?

回答

5

因为macro_rules!比您预期的有点笨拙。例如,它不会在扩展某些东西时带入进口产品。最好把宏观扩展看作,主要是只是一个愚蠢的复制+粘贴工作。

如果你看看任何依赖于外部符号的写得很好的宏,你会看到诸如::std::result::Result而不是Result之类的东西。这是因为宏观作家不能依靠Result这意味着他们在扩张背景下所期待的。所以第一步是绝对地限定路径。

第二件要知道的事情是,每个宏扩展都会得到一个$crate替换值,该替换值是定义该宏的条目的路径。您可以使用它来访问,例如DbaxError,作为$crate::DbaxError

最后,你很幸运;给定的扩展,你可以作弊一点,只需添加use项目里面的扩展:

#[macro_export] 
macro_rules! dbax_call_test { 
    ($func: expr) => { 
     { 
      use std::ffi::CString; 
      use $crate::dbax_function; 
      let call_c_func = unsafe { dbax_function(CString::new($func).unwrap().as_ptr(),0) }; 
      // ... 
     } 
    } 
} 
相关问题