यह ट्यूटोरियल functions और function-like macros के बीच के अंतर को स्पष्ट करता है। उदाहरण के लिए, msg! के बाद विस्मयादिबोधक चिह्न (exclamation point) क्यों होता है? यह ट्यूटोरियल इस सिंटैक्स को समझाएगा।
एक strongly typed भाषा होने के कारण, Rust किसी function में arbitrary संख्या में arguments को स्वीकार नहीं कर सकता है।
उदाहरण के लिए, Python का print function arbitrary संख्या में arguments को स्वीकार कर सकता है:
print(1)
print(1, 2)
print(1, 2, 3)
! यह दर्शाता है कि “function” वास्तव में एक function-like macro है।
Rust में function-like macros की पहचान ! प्रतीक की उपस्थिति से की जाती है, उदाहरण के लिए println!(...) या Solana में msg!(...)।
Rust में, कुछ प्रिंट करने के लिए एक सामान्य function (function-like macro नहीं) std::io::stdout().write है और यह argument के रूप में केवल एक सिंगल byte string को ही स्वीकार करता है।
यदि आप निम्नलिखित कोड को चलाना चाहते हैं, और आप अपना development environment सेट नहीं करना चाहते हैं, तो Rust Playground एक सुविधाजनक टूल है।
आइए निम्नलिखित उदाहरण का उपयोग करें (यहाँ से लिया गया है):
use std::io::Write;
fn main() {
std::io::stdout().write(b"Hello, world!\n").unwrap();
}
ध्यान दें कि write एक function है, कोई macro नहीं क्योंकि इसमें ! नहीं है।
यदि आप Python में ऊपर किए गए कार्य को यहाँ करने का प्रयास करते हैं, तो कोड compile नहीं होगा क्योंकि write केवल एक ही argument स्वीकार करता है:
// this does not compile
use std::io::Write;
fn main() {
std::io::stdout().write(b"1\n").unwrap();
std::io::stdout().write(b"1", b"2\n").unwrap();
std::io::stdout().write(b"1", b"2", b"3\n").unwrap();
}
इस प्रकार, यदि आप arbitrary संख्या में arguments को प्रिंट करना चाहते हैं, तो आपको arguments की प्रत्येक संख्या के लिए प्रत्येक मामले को संभालने हेतु एक कस्टम print function लिखना होगा — जो कि अत्यधिक inefficient है!
यहाँ बताया गया है कि ऐसा कोड कैसा दिखेगा (इसकी बिल्कुल भी अनुशंसा नहीं की जाती है!):
use std::io::Write;
// print one argument
fn print1(arg1: &[u8]) -> () {
std::io::stdout().write(arg1).unwrap();
}
// print two arguments
fn print2(arg1: &[u8], arg2: &[u8]) -> () {
let combined_vec = [arg1, b" ", arg2].concat();
let combined_slice = combined_vec.as_slice();
std::io::stdout().write(combined_slice).unwrap();
}
// print three arguments
fn print3(arg1: &[u8], arg2: &[u8], arg3: &[u8]) -> () {
let combined_vec = [arg1, b" ", arg2, b" ", arg3].concat();
let combined_slice = combined_vec.as_slice();
std::io::stdout().write(combined_slice).unwrap();
}
fn main() {
print1(b"1\n");
print2(b"1", b"2\n");
print3(b"1", b"2", b"3\n");
}
यदि हम print1, print2, print3 functions में एक पैटर्न खोजते हैं, तो यह केवल arguments को एक vector में डालता है और उनके बीच एक स्पेस जोड़ता है, फिर vector को वापस एक bytes string (सटीक रूप से कहें तो bytes slice) में बदल देता है।
क्या यह अच्छा नहीं होगा यदि हम println! जैसे कोड के एक हिस्से को लें और इसे स्वचालित रूप से एक ऐसे print function में expand कर दें जो ठीक उतने ही arguments लेता है जितने हमें चाहिए?
यही काम एक Rust macro करता है।
एक Rust macro, Rust कोड को इनपुट के रूप में लेता है और प्रोग्रामेटिक रूप से इसे और अधिक Rust कोड में expand कर देता है।
यह हमें उस ऊब से बचने में मदद करता है जहाँ हमें अपने कोड के लिए आवश्यक हर प्रकार के print स्टेटमेंट के लिए एक नया print function लिखना पड़ता है।
Macro को expand करना
यह देखने के लिए कि Rust कंपाइलर कैसे println! macro को expand कर रहा है, इसका उदाहरण देखने के लिए cargo expand github रेपो देखें। इसका परिणाम काफी विस्तृत (verbose) है इसलिए हम इसे यहाँ नहीं दिखाएंगे।
Macros को black boxes के रूप में मानना ठीक है
जब किसी लाइब्रेरी द्वारा प्रदान किए जाते हैं तो macros बहुत उपयोगी होते हैं, लेकिन इन्हें हाथ से लिखना बहुत थकाऊ (tedious) होता है क्योंकि इसके लिए सचमुच Rust कोड को parse करने की आवश्यकता होती है।
Rust में विभिन्न प्रकार के macros
हमने println! के साथ जो उदाहरण दिया है वह एक function-like macro है। Rust में अन्य प्रकार के macros भी होते हैं लेकिन अन्य दो जिनकी हमें परवाह है वे custom derive macro और attribute-like macro हैं।
आइए anchor द्वारा बनाए गए एक नए प्रोग्राम पर नज़र डालें:

हम अगले ट्यूटोरियल में समझाएंगे कि ये कैसे काम करते हैं।
RareSkills के साथ और जानें
यह ट्यूटोरियल हमारे मुफ़्त Solana course का हिस्सा है।
मूल रूप से 15 फरवरी, 2024 को प्रकाशित