为什么我必须在客户端库中公开宏实现的“使用”?

时间:2015-06-19 17:25:14

标签: macros rust

我正在尝试使用我在单独模块中创建的宏。参考this SO question,我已经导入了一个宏。但似乎我有

更新以添加宏实施

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

中的扩展“包括”的一部分,不应该生锈

1 个答案:

答案 0 :(得分:6)

因为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) };
            // ...
        }
    }
}