我正在尝试使用我在单独模块中创建的宏。参考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
答案 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) };
// ...
}
}
}