0Pricing
Learn Rust Coding · 课时

过程宏:派生宏与函数宏

深入了解过程宏,包括自定义 `#[derive]` 宏和函数式宏,用于生成更复杂的代码。

过程宏:派生宏与函数宏 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 3 节课。

过程宏简介

欢迎来到过程宏的世界!与声明式宏(macro_rules!)不同,过程宏类似于直接处理 Rust 代码本身的函数。

它们接收一个 TokenStream 作为输入,处理后返回另一个 TokenStream。这使得它们能够生成复杂得多的代码。

过程宏的类型

Rust 提供三种主要的过程宏:

  • 类函数宏:它们看起来和行为都像普通的函数调用,例如 my_macro!(...)。
  • 派生宏:您可以使用 #[derive(MyTrait)],为结构体和枚举自动实现特征。
  • 属性宏:您可以定义自定义属性,并将其应用于项目,例如 #[route("/path")]。

`proc-macro` crate

过程宏必须位于专用的 crate 类型中。在您的 Cargo.toml 中,可以这样声明:

这会告诉 Cargo,该 crate 包含在编译时转换代码的宏。

[package]
name = "my_macros"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

类函数宏详解

类函数宏通过函数上的 #[proc_macro] 属性定义。该函数接收一个 proc_macro::TokenStream,并返回一个 proc_macro::TokenStream。

它们适合用于自定义领域专用语言(DSL),或用于处理 macro_rules! 无法完成的复杂代码重复。

use proc_macro::TokenStream;

#[proc_macro]
pub fn my_function_macro(input: TokenStream) -> TokenStream {
    // Logic to transform input TokenStream
    // ...
    input // For example, return the input unchanged
}

类函数宏示例

下面是一个概念性示例。宏 `greet_name!` 会生成一条打印语句。实际实现需要解析输入的 TokenStream,以提取名称。

虽然宏的定义很复杂,但使用起来简单而强大:

/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;

#[proc_macro]
pub fn greet_name(input: TokenStream) -> TokenStream {
    // Imagine parsing 'input' to get a name like 'World'
    // and generating: println!("Hello, World!");
    "println!(\"Hello, {}!\", \"CoddyKit\");".parse().unwrap()
}

/* In 'my_app/src/main.rs' */
use my_macros::greet_name;

fn main() {
    greet_name!("CoddyKit");
}

理解 `#[derive]` 宏

派生宏是最常见的类型。它们允许您为结构体或枚举自动实现特征。

当您编写 #[derive(Debug)] 时,宏会在编译时运行,生成必要的代码,使您的类型实现 Debug 特征。

实现 `#[derive]`(概念)

自定义派生宏通常使用 syn(用于将 Rust 代码解析为 AST)和 quote(用于根据 AST 生成 Rust 代码)等库来构建。

您需要定义一个带有 #[proc_macro_derive(MyTrait)] 注解的函数。该函数接收表示结构体或枚举的 TokenStream,并返回生成的特征实现。

/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;

#[proc_macro_derive(MyDebug)] // MyDebug is the trait name
pub fn my_debug_derive(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    let name = &ast.ident;

    let expanded = quote! {
        impl std::fmt::Debug for #name {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                f.debug_struct(stringify!(#name)).finish()
            }
        }
    };
    expanded.into()
}

使用 `#[derive(Debug)]` 的示例

让我们来看一个您很可能已经使用过的派生宏实际示例:Debug。通过向 Point 结构体添加 #[derive(Debug)],Rust 会自动实现 Debug 特征,让我们能够以清晰易读的方式打印其内容。

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 10, y: 20 };
    println!("My point is: {:?}", p);
}

属性宏:`#[my_attribute]`

属性宏与派生宏类似,但可以应用于任何项目(函数、结构体、模块等)。它们会接收所附加的项目,以及括号中的任意参数作为输入。

常见用途包括 Web 框架路由(例如 #[get("/users")])或测试设置(例如 #[test])。

/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn log_calls(attr: TokenStream, item: TokenStream) -> TokenStream {
    // Imagine adding println! statements to 'item'
    item
}

/* In 'my_app/src/main.rs' */
use my_macros::log_calls;

#[log_calls("entry_point")]
fn my_function() {
    println!("Inside my_function");
}

fn main() {
    my_function();
}

何时使用哪种宏

  • 类函数宏:用于自定义小型语言,或转换任意代码块的复杂操作。
  • 派生宏:用于为结构体和枚举自动实现特征。
  • 属性宏:根据自定义属性,修改特定项目(函数、结构体)周围的代码,或生成相关代码。

每种类型都有独特的用途,可以扩展 Rust 的语法和功能。

快速检查:宏的类型

关于过程宏,以下哪些说法是 TRUE?

回顾:代码生成的力量

您已经探索了过程宏的高级世界!

  • 我们学习了用于自定义语法的类函数宏。
  • 我们了解了#[derive] 宏如何自动实现特征。
  • 我们简要了解了用于项目级代码生成的属性宏。

过程宏是减少样板代码和扩展 Rust 功能的强大工具,让您能够编写生成代码的代码!

常见问题解答

「过程宏:派生宏与函数宏」课时是免费的吗?

是的 — 「过程宏:派生宏与函数宏」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 3 节课。

「过程宏:派生宏与函数宏」这节课中我会学到什么?

深入了解过程宏,包括自定义 `#[derive]` 宏和函数式宏,用于生成更复杂的代码。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。

「过程宏:派生宏与函数宏」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 声明式宏(`macro_rules!`)
  2. 过程宏:派生宏与函数宏
  3. 与不安全 Rust 交互
← 返回 Learn Rust Coding