面试题答案
一键面试Rust宏实现
macro_rules! process_collection {
($collection:expr, $operation:expr) => {
{
for item in $collection.iter() {
let result = $operation(item);
println!("{:?}", result);
}
}
};
}
fn square(x: &i32) -> i32 {
*x * *x
}
可以这样调用:
fn main() {
let vec = vec![1, 2, 3];
process_collection!(vec, |x| square(x));
// 如果要处理HashMap,需要先迭代其值
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(1, 10);
map.insert(2, 20);
process_collection!(map.values(), |x| square(x));
}
宏相比于普通函数和trait的优势与劣势
优势
- 灵活性:宏可以操作语法树,能接受更灵活的输入,比如在上述宏中可以接受任意可迭代的集合类型,而普通函数和trait在处理不同集合类型时需要更多样板代码来处理泛型约束。
- 编译期计算:宏在编译期展开,可以进行编译期计算,比如生成特定代码结构。而普通函数和trait在运行时执行,无法利用编译期的优化。
劣势
- 可读性:宏展开后的代码可读性较差,尤其是复杂宏,很难从展开后的代码直观理解其逻辑。而普通函数和trait的代码结构清晰,易于理解和维护。
- 调试困难:由于宏在编译期展开,调试宏错误比调试普通函数和trait更困难,因为错误信息通常基于展开后的代码,定位问题根源相对复杂。
- 类型检查延迟:宏在展开时不进行严格的类型检查,直到展开后的代码被编译才进行类型检查,可能导致一些难以排查的类型错误。而普通函数和trait在定义时就进行严格的类型检查。