Почему я должен выставлять "использование" реализации макроса в клиентской библиотеке?

Я пытаюсь использовать макрос, который я создал в отдельном модуле. Со ссылкой на этот вопрос, я импортировал макрос нормально. Однако, похоже, у меня есть

Обновление для добавления реализации макроса

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) };
            // ...
        }
    }
}
Другие вопросы по тегам