
21 宏、注解、类型转换
即所谓的元编程(metaprogramming)。这些宏以 展开 的方式来生成比你所手写出的更多的代码。
因为编译器会进行多次扫描,将定义信息自动提到前边,而宏代码的运行在编译器执行的同时,所以编译器没法在执行宏之前提取宏到前边,宏代码在哪里,那么就什么时候执行宏。
这样性能虽然很差,但是宏本来就不是用来执行需要性能的事情,宏要做的是提供最强大的功能性即可。
声明宏 macro_rules!
其核心概念是,声明宏允许我们编写一些类似 Rustmatch 表达式的代码。将一个值(传入代码字面)和包含相关代码的模式用于和前面提到的源代码字面值进行比较,一旦匹配成功,每个模式的相关代码会替换传递给宏的代码。
模式匹配母板 => 宏代码体;
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
[!warning] 注意要使用#[macro_export]注解,表明这个宏是独立的,导入即可用
如果没有该注解,这个宏不能被引入作用域。(对于中间宏来说,只是某些宏的private宏,不能独立使用)
模式匹配母板
首先,一对括号包含了整个模式。我们使用美元符号($)在宏系统中声明一个变量来包含匹配该模式的 Rust 代码。美元符号明确表明这是一个宏变量而不是普通 Rust 变量。
首先,一对括号包含了整个模式。() =>
使用美元符号($)在宏系统中声明一个变量来包含匹配该模式的 Rust 代码。
( $()) =>
$() 内则是 $x:expr ,其匹配 Rust 的任意表达式,并将该表达式命名为 $x。
( $($x:expr) )=>
在 $() 之后的逗号表示在每个与 $() 内代码匹配的实例之间必须出现一个字面量逗号分隔符。
($($x:expr),) =>
紧随逗号之后的 * 说明该模式匹配零个或更多个 * 之前的任何模式。
($($x:expr),) =>
宏代码块
边界{}
某匹配分支模块 ()=>{};
分支模块的返回表达式 {代码块表达式}
macro_rules! name {
()=>{
{
expr
}
};
}
$( temp_vec.push($x); )*表示模式匹配了多少次,这里就执行多少次,并且$x就是对应序号的模式匹配的值。
过程宏
过程宏这个函数接收的参数和返回值都是TokenStream(令牌流)——也就是编译器眼中的“代码碎片”。
为了处理输入,你必须引入 syn 库把它解析成 Rust 的抽象语法树(AST),比如解析成 DeriveInput 结构体。然后你遍历这个结构体,用 quote 库把想生成的代码重新拼成 TokenStream 返回。
派生宏 derive
派生宏的作用就是帮助我们一键完善、补充定义、实现。
属性宏
可以让我们专注于内部核心代码的书写。
类函数宏
例如sql,像sql!("SELECT * FROM users")。它在编译期解析你传进去的字符串(比如 SQL),检查语法是否正确,甚至提前生成数据库访问代码。
条件编译
feature 特性
feature 是为了“按需启用”依赖库中的特定功能模块,从而精准控制编译时间、最终二进制文件大小,以及是否引入额外的系统依赖。
// 只有当 "webp" feature 被启用时,这个模块才会被编译
#[cfg(feature = “webp”)]
pub mod webp;
然后消费者就能通过feature指定引用库的那些部分。
“default” 是一个特殊特性,默认会被启用default = ["ico"]
[dependencies]
my_image_processor = "0.1.0"
# 或者,显式启用特定特性
my_image_processor = { version = "0.1.0", features = ["webp"] }
# 或者,禁用默认特性,只启用自己需要的
my_image_processor = { version = "0.1.0", default-features = false, features = ["bmp"] }
类型转换
as 关键字
from trait 非常多的类型都实现了,完全转换
from_into
parse::<T>() parse trait也非常多的类型实现了
FromStr trait也非常多的类型实现了
TryFrom trait也非常的有用,使适用于无法完美转换的类型,由程序员自行决定逻辑。
切片和动态数组,转换成定长数组,需要使用定长数组的try_from
AsRef<T> trait 与 AsMut<T> trait 类型转换成T引用的函数实现 。
