macros!

Mới bắt đầu với Rust chúng ta thường sử dụng rất nhiều macro như println!.

Thực chất có 3 loại macro trong Rust.

  • Custom #[derive] macros that specify code added with the derive attribute used on structs and enums
  • Attribute-like macros that define custom attributes usable on any item
  • Function-like macros that look like function calls but operate on the tokens specified as their argument

Khác nhau giữa Macros và Functions

// Macros

macro_rules! print_message {
    (msg: $msg:expr) => {
        println!("Message: {}", $msg);
    };
}

fn main() {
    print_message!(msg: "Hello, world!");
}
/// Functions
fn print_message(msg: &str) {
    println!("Message: {}", msg);
}

fn main() {
    print_message("Hello, world!");
}

Điểm khác biệt trong thời điểm biên dịch

  • Functions được thực thi trong quá trình thực thi của chương trình, còn Macros được đánh giá và mở rộng trong quá trình biên dịch.
  • Functions chỉ có thể được gọi khi chương trình đang chạy, trong khi Macros có thể được gọi bất kỳ lúc nào trong quá trình biên dịch.

AST (Abstract Syntax Tree)

  • Macros có thể truy cập vào AST của code được viết, cho phép thay đổi code theo cách động.
  • Functions không có quyền truy cập vào AST của code được viết.

Input / Output

Rust MacrosRust Functions
InputToken streamTham số và đối số của hàm
OutputĐoạn mã Rust được mở rộngGiá trị hoặc hiệu ứng sẽ được trả về
macro_rules! math {
    ($x:expr + $y:expr) => { $x * $y };
}

fn main() {
    let result = math!(4 + 5);
    println!("4 * 5 = {}", result);
}

Khi biên dịch, macro math! sẽ được mở rộng và tạo ra đoạn mã 4 * 5 được tính toán thành 20. Tham số của macro lúc này là $x:expr + $y:exprtoken stream, cho phép khả năng mở rộng cú pháp không giới hạn.

Sử dụng và ứng dụng

  • Functions được sử dụng để đóng gói một khối lệnh nhất định, giúp tái sử dụng và quản lý code dễ dàng hơn.
  • Macros được sử dụng để thay đổi code tại thời điểm biên dịch, giúp viết code ngắn gọn và hiệu quả hơn.

Macros mặc định

Standard Macros được định nghĩa bởi compiler và std.

print!, println!, eprint!, eprintln!
format!, format_args!
write!, writeln!

concat!, concat_idents!, stringify // concat_idents: nightly-only experimental API

include!, include_bytes!, include_str!

assert!, assert_eq!, assert_ne!
debug_assert!, debug_assert_eq!, debug_assert_ne!

try!, panic!, compile_error!, unreachable!, unimplemented!

file!, line!, column!, module_path!
env!, option_env!
cfg!

select!, thread_local! // select: nightly-only experimental API

vec!