Rust-এ macros হল একটি শক্তিশালী বৈশিষ্ট্য, যা কোডের পুনরাবৃত্তি কমাতে এবং আপনার কোডের ফাংশনালিটি বৃদ্ধি করতে ব্যবহৃত হয়। Rust-এ দুটি প্রধান ধরনের macro আছে:
- Declarative Macros (Declarative Macros 1.1): এটি সাধারণত
macro_rules!ব্যবহার করে তৈরি করা হয়। - Procedural Macros (Procedural Macros 2.0): এটি কোডের উপর গভীরভাবে কাজ করতে পারে, যেমন ফাংশন এবং অন্যান্য Rust উপাদানকে প্যার্স করে প্রোগ্রাম তৈরি করা।
এখানে আমরা Declarative Macros (যা macro_rules! দিয়ে তৈরি হয়) এবং Procedural Macros-এর মধ্যে Declarative Macros নিয়ে আলোচনা করব।
Declarative Macros তৈরি করা
Declarative Macros Rust-এ সবচেয়ে সাধারণ macro এবং সেগুলি সাধারণত কোড রিপিটেশন দূর করতে ব্যবহৃত হয়। macro_rules! ব্যবহার করে আপনি আপনার কাস্টম macro তৈরি করতে পারেন।
১. Basic Macro:
আমরা শুরু করব একটি সহজ macro দিয়ে যা একটি নির্দিষ্ট মানকে প্রিন্ট করবে।
macro_rules! say_hello {
() => {
println!("Hello, World!");
};
}
fn main() {
say_hello!(); // Output: Hello, World!
}এখানে, say_hello! একটি macro যা কোনো ইনপুট ছাড়াই একটি "Hello, World!" বার্তা প্রিন্ট করবে।
২. Parameters সহ Macro:
অধিকাংশ সময়, আপনি macros ব্যবহার করবেন যেগুলোর ইনপুট প্যারামিটার থাকে। এটি ব্যবহারকারীর কাছ থেকে কিছু ইনপুট গ্রহণ করে কোড জেনারেট করতে সাহায্য করবে।
macro_rules! create_point {
// 2টি প্যারামিটার নিয়ে একটি tuple স্টাইলের struct তৈরি করা হবে।
($x:expr, $y:expr) => {
( $x, $y )
};
}
fn main() {
let point = create_point!(5, 10);
println!("Point: ({}, {})", point.0, point.1);
}এখানে create_point! macro দুটি প্যারামিটার নেয় এবং একটি tuple তৈরি করে দেয়, যা পরে ব্যবহার করা হয়।
৩. Multiple Patterns (একাধিক প্যাটার্ন) সহ Macro:
একটি macro বিভিন্ন ধরনের প্যাটার্ন গ্রহণ করতে পারে এবং সেই অনুযায়ী কাজ করতে পারে। এটি কোডকে আরও রি-ইউজেবল এবং ইউনিভার্সাল বানাতে সাহায্য করে।
macro_rules! print_values {
// প্রথম প্যাটার্ন
($x:expr, $y:expr) => {
println!("x: {}, y: {}", $x, $y);
};
// দ্বিতীয় প্যাটার্ন
($x:expr, $y:expr, $z:expr) => {
println!("x: {}, y: {}, z: {}", $x, $y, $z);
};
}
fn main() {
print_values!(1, 2); // Output: x: 1, y: 2
print_values!(1, 2, 3); // Output: x: 1, y: 2, z: 3
}এখানে, print_values! macro দুটি বা তিনটি প্যারামিটার নেবে এবং সেই অনুযায়ী আউটপুট প্রিন্ট করবে।
৪. Macro with Recursion:
Rust-এ macros-এ রিকার্সনও ব্যবহার করা যেতে পারে, যাতে আপনি আরও জটিল সমস্যা সমাধান করতে পারেন।
macro_rules! calculate_sum {
// Base case
($x:expr) => {
$x
};
// Recursive case
($x:expr, $($rest:expr),*) => {
$x + calculate_sum!($($rest),*)
};
}
fn main() {
let sum = calculate_sum!(1, 2, 3, 4, 5);
println!("Sum: {}", sum); // Output: Sum: 15
}এখানে, calculate_sum! macro একটি রিকার্সিভ প্যাটার্ন ব্যবহার করে একাধিক ইনপুটের যোগফল বের করছে।
Procedural Macros তৈরি করা
Procedural Macros অনেক বেশি শক্তিশালী এবং এগুলি সাধারণত কোডের প্যাটার্ন প্যার্স করে এবং ট্রান্সফর্ম করে। Procedural Macros তৈরি করতে আপনাকে একটি আলাদা ক্রেট (লিব্রেরি ক্রেট) তৈরি করতে হবে যা proc-macro ক্রেট হিসেবে চিহ্নিত হবে।
Procedural Macros ব্যবহার করা:
- Rust Procedural Macro Crate তৈরি করা:
প্রথমে, একটি নতুন লাইব্রেরি ক্রেট তৈরি করুন।
cargo new my_macro --lib cd my_macro
Cargo.toml ফাইল আপডেট করা:
আপনার Cargo.toml ফাইলে
proc-macroফিচারটি সক্রিয় করুন:[lib] proc-macro = trueProcedural Macro কোড লেখা:
উদাহরণস্বরূপ, আমরা একটি procedural macro তৈরি করব যা একটি struct এ প্রিন্ট করার ফাংশন যোগ করবে।
extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro] pub fn print_struct(input: TokenStream) -> TokenStream { let input_str = input.to_string(); let output = format!( "fn print() {{ println!(\"Struct: {}\"); }}", input_str ); output.parse().unwrap() }Procedural Macro ব্যবহার করা:
এবার, আপনি এই procedural macro অন্য একটি ক্রেট থেকে ব্যবহার করতে পারবেন।
সারাংশ
Custom Macros Rust-এ কোড পুনরাবৃত্তি কমাতে এবং আপনার কোডে আরও ফাংশনালিটি যোগ করতে একটি শক্তিশালী টুল। আপনি macro_rules! দিয়ে declarative macros তৈরি করতে পারেন, যা প্যাটার্ন মেচিংয়ের মাধ্যমে কোড জেনারেট করে। এর পাশাপাশি procedural macros আরও গভীরভাবে কাজ করে, এবং ট্রান্সফর্মেশন বা কোড জেনারেশন করার জন্য ব্যবহৃত হয়। Rust-এ macros একটি শক্তিশালী বৈশিষ্ট্য, যা আপনার কোডের দক্ষতা এবং মেইনটেনেবিলিটি বৃদ্ধি করতে সাহায্য করে।
Read more