In this blog post, let us explore more in detail how to work with Macros
in Rust
What are Macros?
Macros are a way of writing code that writes other code, which is known as metaprogramming
Metaprogramming is useful for reducing the amount of code you write and maintain, which is also one of the roles of functions. However, macros have some additional powers that functions don’t.
Types of Macros
There are two kinds of macros: Declarative and Procedural
Declarative Macros
It is a most used form of macros in Rust. Also referred to as “macros by example”, “macro_rules! macros”. Allows you to write something similar to match expression
To define a macro, we use macro_rules! Construct. We use #[macro_export] annotation to indicate that this macro should be made available whenever the crate in which the macro is defined is brought into scope.
Declarative Macros Syntax
#[macro_export]
macro_rules! <name of macro> {
( $( $x:expr ),* ) => {
{
<implementation>
}
};
}
Procedural Macros
It acts more like a function (and is a type of procedural)
Accepts some code as an input, operates on that code, and produces some code as an output rather than matching against patterns and replacing the code with other code as declarative macros do.
Three kinds of procedural macros:
Derive
Derive macros define new inputs for the derive attribute. These macros can create new items given the token stream of a struct, enum, or union. They can also derive macro helper attributes.
Derive Procedural Macros Syntax
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(<Name of Derive Macro>)]
pub fn derive_macro(_item: TokenStream) -> TokenStream {
<Implementation>
}
Attribute-like
Attribute macros define new outer attributes which can be attached to items, including items in extern blocks, inherent and trait implementations, and trait definitions.
Attribute Procedural Macros Syntax
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn <Attribute Name>(_attr: TokenStream, item: TokenStream) -> TokenStream {
<Implementation>
}
Function-like
Function-like procedural macros are procedural macros that are invoked using the macro invocation operator (!)
Function-like Procedural Macros Syntax
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn <Macro Name>(_item: TokenStream) -> TokenStream {
<Implementation>
}
Macros vs Functions
Macros are more complex to implement than function definitions because we’re writing Rust code that writes Rust code.
Macro definitions are generally more difficult to read, understand and maintain than function definitions
Macros must define first or bring them into scope before you call in a file, as opposed to functions you can define anywhere and call anywhere
Please feel free to share your comments if any
Happy reading!!!
Top comments (0)