2016-02-23 16 views
7

मेरे पास एक मैक्रो है जो फ़ंक्शन घोषणाओं की एक सूची लेता है और उन्हें विभिन्न घोषणाओं में बदल देता है।मैं विभिन्न प्रकार के कार्यों पर जंग जंग का सामान्यीकरण कैसे करूं?

macro_rules! re_export { 
    ($(pub fn $i:ident($($arg:ident: $argty:ty)*) -> $ret:ty;)*) => ($(
     extern { 
      pub fn $i($($arg: $argty),*) -> $ret; 
     } 
    )*); 
    ($(pub fn $i:ident($($arg:ident: $argty:ty)*);)*) => ($(
     extern { 
      pub fn $i($($arg: $argty),*); 
     } 
    )*); 
} 

कौन इस तरह प्रयोग किया जाता है:

re_export! { 
    pub fn abs(i: c_int) -> c_int; 
    pub fn rand() -> c_int; 
    pub fn foo(); 
    pub fn add(i: c_int, j: c_int) -> c_int; 
} 

मैं मैक्रो कैसे सामान्यीकरण ताकि मैं के साथ या आर्ग के बिना यह कई कार्यों देने के लिए और प्रकार लौट सकते हैं और यह उन सभी को इस पर काम कर सकते हैं कर सकते हैं। एक मैक्रो बनाना आसान है जो एक ही प्रकार के कई कार्यों पर काम करता है, लेकिन मैं यह नहीं समझ सकता कि इसे विभिन्न प्रकारों के लिए कैसे काम करना है।

उत्तर

9

ठीक है, दो तरीके हैं।

आप इस सटीक वाक्य रचना पार्स करने के लिए चाहते हैं, तो आप एक muncher का उपयोग करना होगा। तो, कुछ की तरह:

macro_rules! re_export { 
    () => {}; 

    (
     pub fn $i:ident($($arg:ident: $argty:ty)*) -> $ret:ty; 
     $($tail:tt)* 
    ) => { 
     extern { 
      pub fn $i($($arg: $argty),*) -> $ret; 
     } 
     re_export! { $($tail)* } 
    }; 

    (
     pub fn $i:ident($($arg:ident: $argty:ty)*); 
     $($tail:tt)* 
    ) => { 
     extern { 
      pub fn $i($($arg: $argty),*); 
     } 
     re_export! { $($tail)* } 
    }; 
} 

यह एक समय में एक समारोह हस्ताक्षर बंद तोड़ने शामिल है उन्हें रिकर्सिवली प्रसंस्करण,। यह चीजों को पार्स करने का सबसे लचीला तरीका है, लेकिन का मतलब है कि आप मैक्रो रिकर्सन सीमा के विरुद्ध दौड़ सकते हैं। डिफ़ॉल्ट सीमा 64 है, इसलिए यदि आपके पास उससे अधिक इनपुट है, तो आपको कई शीर्ष-स्तरीय मैक्रो इनोकेशन की आवश्यकता होगी, या आपको अपने क्रेट में #![recursion_limit="128"] विशेषता जोड़कर रिकर्सन सीमा को मैन्युअल रूप से उठाना होगा।

दूसरा सिंटैक्स को बदलना है ताकि आप विभाजन कर सकें और फिर हस्ताक्षर को दो चरणों में संसाधित कर सकें। ऐसा करने के लिए, हस्ताक्षर के लिए आपके पास कुछ प्रकार के नियमित शीर्ष-स्तरीय वाक्यविन्यास होना चाहिए। उदाहरण के लिए:

macro_rules! re_export { 
    ($({$($sigs:tt)*})*) => { 
     $(
      re_export! { @fn $($sigs)* } 
     )* 
    }; 

    (@fn pub fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty) => { 
     extern { 
      pub fn $i($($arg: $argty),*) -> $ret; 
     } 
    }; 

    (@fn pub fn $i:ident($($arg:ident: $argty:ty),*)) => { 
     extern { 
      pub fn $i($($arg: $argty),*); 
     } 
    }; 
} 

यहाँ, हम {...} रों में प्रत्येक कार्य हस्ताक्षर लपेट दें। ऐसा इसलिए है क्योंकि मैचर समूह ((...), [...], और {...}) macro_rules! को उनकी सामग्री को अंधाधुंध रूप से समझने के बिना, उन्हें समझने के बिना अनुमति दें। यह हमें नियमित रूप से अनियमित फ़ंक्शन हस्ताक्षर से मिलान करने की अनुमति देता है। शीर्ष-स्तर विस्तार केवल वास्तविक प्रसंस्करण के लिए प्रत्येक व्यक्तिगत फ़ंक्शन हस्ताक्षर को आगे बढ़ाता है। @fn यह सुनिश्चित करने के लिए कि हम रिकर्सन के दौरान सही नियम चुनते हैं, केवल internal rule मार्कर है।

यह वही प्रत्यावर्तन सीमा है कि पिछले एक नहीं होते हैं ... लेकिन आप एक थोड़ा सुस्त सिंटैक्स का उपयोग करने की आवश्यकता है:

re_export! { 
    { pub fn abs(i: c_int) -> c_int } 
    { pub fn rand() -> c_int } 
    { pub fn foo() } 
    { pub fn add(i: c_int, j: c_int) -> c_int } 
} 
+0

मैं अपने उपयोगकर्ता नाम से मान लेंगे कि आप पुस्तक लिखी है कि आप जुड़े यह काफी अच्छा है! मेरी इच्छा है कि जब मैं इस प्रश्न के लिए शोध कर रहा था तो Google ने मुझे यह सुझाव दिया होगा। – Mastax