2015-06-19 7 views
5

Sto provando a utilizzare una macro che ho creato in un modulo separato. Con riferimento a this SO question, ho importato una macro fine. Tuttavia sembra che hoPerché devo esporre l''uso' di una macro implementazione nella libreria client?

aggiornamento per aggiungere macro realizzazione

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())) 
      } 
     } 

    } 
} 

e main.rs in una cassa separata

// 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"); 
} 

Questo funziona bene, ma le linee use std::* fanno tutti parte dell'implementazione nello lib.rs.

Perché devo esporre l''uso' dell'implementazione nella libreria client? Non dovrebbe arrugginire come parte della sua espansione 'includere' qualsiasi cosa fosse nello lib.rs?

risposta

5

Perché macro_rules! è un po 'più stupido di quanto ci si potrebbe aspettare. Ad esempio, non porta con sé le importazioni quando espande qualcosa. È meglio pensare all'espansione delle macro come per lo più solo un lavoro di copia e incolla.

Se si osserva una macro ragionevolmente ben scritta che dipende da simboli esterni, verranno visualizzate le cose come ::std::result::Result anziché Result. Questo perché il macro writer non può dipendere dal significato di Result che cosa si aspettano nel contesto di espansione. Quindi il primo passo è qualificare i percorsi assolutamente.

La seconda cosa da sapere è che ogni espansione di macro ottiene una sostituzione $crate che rappresenta il percorso della cassa in cui è stata definita la macro. È possibile utilizzare questo per accedere, ad esempio, DbaxError come $crate::DbaxError.

Infine, sei fortunato; data l'espansione, si può imbrogliare un po 'e basta aggiungere gli elementi useall'interno l'espansione:

#[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) }; 
      // ... 
     } 
    } 
} 
Problemi correlati