Rust 中的宏主要分为两大类:声明宏和过程宏。

什么是属性宏

属性宏(Attribute Macro)是 Rust 的一种 过程宏(Procedural Macro),允许你在编译时修改或生成代码。它的特点是通过 #[...] 语法附加到代码项(如函数、结构体、模块等)上,接收属性参数和代码项本身作为输入,然后生成新的代码。

属性宏可以分为两种类型:

• 内建属性宏(Built-in Attribute Macros):由 Rust 编译器提供,用于控制编译器的行为或提供特定的功能。

• 自定义属性宏(Custom Attribute Macros):由用户或第三方库定义,用于扩展 Rust 的功能或实现特定的逻辑。

常见的场景属性宏

以下是一些常见的内建属性宏及其应用场景:

(1)#[cfg]

• 作用:用于条件编译,根据特定的配置条件决定是否编译某段代码。

• 示例:

rust 复制代码
#[cfg(target_os = "linux")]
fn foo() {
    println!("Running on Linux");
}

#[cfg(target_os = "windows")]
fn foo() {
    println!("Running on Windows");
}

fn main() {
    foo();
}

• 场景:跨平台开发时,根据不同的操作系统或目标环境编译不同的代码。

(2)#[derive]

• 作用:为类型自动派生实现某些标准 trait(如DebugClonePartialEq等)。

• 示例:

rust 复制代码
#[derive(Debug, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

• 场景:快速为类型实现标准 trait,减少样板代码。

(3)#[test]

• 作用:标记一个函数为测试函数,该函数将在运行测试时被调用。

• 示例:

rust 复制代码
#[test]
fn test_addition() {
    assert_eq!(2 + 2, 4);
}

• 场景:单元测试和集成测试。

(4)#[allow]#[warn]

• 作用:用于控制编译器的警告和错误提示。

• 示例:

rust 复制代码
#[allow(dead_code)]
fn unused_function() {
    println!("This function is not used");
}

• 场景:在开发过程中忽略某些特定的警告,或者强制某些警告提升为错误。

(5)#[repr]

• 作用:指定类型在内存中的表示形式。

• 示例:

rust 复制代码
#[repr(u8)]
enum Color {
    Red = 0,
    Green = 1,
    Blue = 2,
}

• 场景:与外部系统交互时,确保类型在内存中的布局与外部系统一致。

(6)#[no_mangle]

• 作用:禁止编译器对函数名或变量名进行名称修饰(mangling),保留其原始名称。

• 示例:

rust 复制代码
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
    a + b
}

• 场景:与 C 语言代码交互时,确保函数名与 C 语言中的名称一致。

属性宏与派生宏的关系

(1)定义

• 派生宏(Derive Macros):是一种特殊的属性宏,用于为类型(如结构体或枚举)自动派生实现某些 trait。它们的语法是#[derive(TraitName)]

• 属性宏(Attribute Macros):更广泛的概念,包括派生宏和其他类型的属性宏。属性宏的语法是#[attribute_name]

(2)关系

• 派生宏是属性宏的一个子集:派生宏是属性宏的一种特殊形式,专门用于实现 trait。

• 属性宏的功能更广泛:除了派生宏的功能外,属性宏还可以用于控制编译器行为、生成代码、修改代码语义等。

(3)区别

• 用途:

派生宏:主要用于为类型自动实现标准 trait,减少样板代码。

属性宏:用途更广泛,包括条件编译、测试、控制编译器行为等。

• 语法:

派生宏:#[derive(Debug, Clone, PartialEq)]

属性宏:#[cfg(target_os = "linux")]#[test]#[allow(dead_code)]等。

常用的内置派生宏

Rust 中内置的派生宏主要有以下几个:

1. Debug

  • 作用 :为结构体或枚举体实现 Debug trait,允许使用调试格式打印,通常使用宏 {:?}{:#?} 来格式化输出。这在调试时非常有用,可以方便地查看变量的值。
  • 示例
rust 复制代码
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 1, y: 2 };
    println!("p is {:?}", p);
    println!("p is {:#?}", p);
}

2. Clone

  • 作用 :为结构体或枚举体实现 Clone trait,允许通过调用 clone() 方法来创建一个类型副本。
  • 示例
rust 复制代码
#[derive(Clone)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    let person1 = Person {
        name: String::from("Alice"),
        age: 30,
    };
    let person2 = person1.clone();
    println!("person1: name = {}, age = {}", person1.name, person1.age);
    println!("person2: name = {}, age = {}", person2.name, person2.age);
}

3. Copy

  • 作用 :为标量类型组合(如元组或包含全部为 Copy 类型的结构体)实现 Copy trait,使得值在赋值或传递时会进行浅复制,而原始值仍然可用。
  • 示例
rust 复制代码
#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1;
    println!("p1: x = {}, y = {}", p1.x, p1.y);
    println!("p2: x = {}, y = {}", p2.x, p2.y);
}

4. PartialEq

  • 作用 :为结构体或枚举体实现 PartialEq trait,允许进行相等比较,使用 ==!= 操作符。
  • 示例
rust 复制代码
#[derive(PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 1, y: 2 };
    let p3 = Point { x: 3, y: 4 };
    println!("p1 == p2: {}", p1 == p2);
    println!("p1 == p3: {}", p1 == p3);
}

5. Eq

  • 作用 :在实现 PartialEq 的基础上,进一步实现 Eq trait,表明该类型满足相等关系的等价性(即满足自反性、对称性和传递性)。只有当所有字段都实现了 Eq 时,才可以为该类型派生 Eq。
  • 示例
rust 复制代码
#[derive(PartialEq, Eq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 1, y: 2 };
    let p3 = Point { x: 3, y: 4 };
    println!("p1 == p2: {}", p1 == p2);
    println!("p1 == p3: {}", p1 == p3);
}

6. PartialOrd

  • 作用 :为结构体或枚举体实现 PartialOrd trait,允许进行大小比较,使用 <<=>>= 操作符。
  • 示例
rust 复制代码
#[derive(PartialOrd, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 1, y: 3 };
    println!("p1 < p2: {}", p1 < p2);
    println!("p1 > p2: {}", p1 > p2);
}

7. Ord

  • 作用 :在实现 PartialOrd 和 Eq 的基础上,进一步实现 Ord trait,表明该类型满足全序关系,即可以进行确定的大小排序。这允许该类型用于需要有序集合的场景,如 BTreeSet 和 BTreeMap。
  • 示例
rust 复制代码
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let mut points = vec![
        Point { x: 2, y: 3 },
        Point { x: 1, y: 2 },
        Point { x: 3, y: 4 },
    ];
    points.sort();
    for p in points {
        println!("({}, {})", p.x, p.y);
    }
}

8. Hash

  • 作用 :为结构体或枚举体实现 Hash trait,允许该类型用于哈希集合(如 HashSet 和 HashMap)的键。
  • 示例
rust 复制代码
use std::collections::HashSet;

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

fn main() {
    let mut set = HashSet::new();
    set.insert(Point { x: 1, y: 2 });
    set.insert(Point { x: 3, y: 4 });
    println!("set contains Point(1,2): {}", set.contains(&Point { x: 1, y: 2 }));
}