Почему я должен выставлять "использование" реализации макроса в клиентской библиотеке?
Я пытаюсь использовать макрос, который я создал в отдельном модуле. Со ссылкой на этот вопрос, я импортировал макрос нормально. Однако, похоже, у меня есть
Обновление для добавления реализации макроса
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
,
Почему я должен выставлять "использование" реализации в клиентской библиотеке? Не должно ржаветь как часть его расширения, "включать" то, что было в lib.rs
?
1 ответ
Так как 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) };
// ...
}
}
}