Rust Macro
Rust Macro Examples.
Function Macro
macro_rules! funcmacro {
() => {
println!("funcmacro");
};
($a: expr, $b: expr) => {
println!("res: {}", $a + $b);
}
}
fn main() {
funcmacro!();
funcmacro!(1, 2);
}
Run Result
✗ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.56s
Running `target/debug/hello`
funcmacro
res: 3
Attribute Macro
Step 1:
[lib]
proc-macro = true
Step 2:
use hello::*;
#[attrmacro]
fn hello() {}
fn main() {
hello();
}
Step 3:
use proc_macro::{TokenStream};
use quote::{quote};
#[proc_macro_attribute]
pub fn attrmacro(_metadata: TokenStream, _input: TokenStream) -> TokenStream {
TokenStream::from(quote!{fn hello() { println!("world")}})
}
Debug Result
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use hello::*;
fn hello() {
{
::std::io::_print(::core::fmt::Arguments::new_v1(&["world\n"], &[]));
}
}
fn main() {
hello();
}
Run Resut
✗ cargo run
warning: unused manifest key: package.proc-macro
Compiling hello v0.1.0 (~/rust-examples/hello)
Finished dev [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/hello`
world
Debug Macro
# 安装 expand
$ cargo install cargo-expand
# 目前仅 nightly 支持
$ rustup install nightly
$ rustup default nightly
# 测试
$ cargo expand --bin hello
Derive Macro
Step 1:
use hello::*;
// drive macro demo
pub trait DeriveMacro {
fn print();
}
#[derive(DeriveMacro)]
struct MyStruct {}
fn main() {
MyStruct::print();
}
Step 2:
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, token::Token, DeriveInput};
#[proc_macro_derive(DeriveMacro)]
pub fn derive_trait(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let expanded = quote! {
impl DeriveMacro for #name {
fn print() {
println!("hello from DeriveMacro")
}
}
};
TokenStream::from(expanded)
}
Run Result
✗ cargo run
Running `target/debug/hello`
hello from DeriveMacro
Full Demo
// lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, token::Token, DeriveInput};
#[proc_macro_attribute]
pub fn attrmacro(_metadata: TokenStream, _input: TokenStream) -> TokenStream {
TokenStream::from(quote! {fn hello() { println!("hello from attribute macro")}})
}
#[proc_macro_derive(DeriveMacro)]
pub fn derive_trait(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let expanded = quote! {
impl DeriveMacro for #name {
fn print() {
println!("hello from derive macro")
}
}
};
TokenStream::from(expanded)
}
// main.rs
use hello::*;
macro_rules! funcmacro {
() => {
println!("hello from function macro");
};
($a: expr, $b: expr) => {
println!("hello from function macro res: {}", $a + $b);
};
}
#[attrmacro]
fn hello() {}
// drive macro demo
pub trait DeriveMacro {
fn print();
}
#[derive(DeriveMacro)]
struct MyStruct {}
fn main() {
funcmacro!();
funcmacro!(1, 2);
hello();
MyStruct::print();
}
# Cargo.toml
[package]
name = "hello"
version = "0.1.0"
edition = "2021"
proc-macro = true
[lib]
proc-macro = true
[dependencies]
syn = {version="1.0.57",features=["full","fold"]}
quote = "1.0.8"
Run Result
✗ cargo run
hello from function macro
hello from function macro res: 3
hello from attribute macro
hello from derive macro