如何在Rust宏变体中按条件添加#[test]或#[should_panic]属性
问题分析与解决方案
你的宏无法正常运行的核心原因是:属性(如#[test])被直接应用在宏调用语句上,而非最终展开的函数项。虽然部分场景下编译器会兼容这种写法,但这并非可靠实现,容易触发编译错误。
修正方案一:复用函数体的宏结构
通过内部宏提取测试逻辑,避免代码重复,同时确保属性直接绑定到函数:
macro_rules! impl_test { // 内部宏:定义测试核心逻辑 (@impl $fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { fn $fn_name() { // 替换为你的实际测试代码 let result = calculate_something($shape, $axis); assert_eq!(result, $ans); } }; // 生成不带测试属性的普通函数 ($fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { impl_test!(@impl $fn_name, $shape, $axis, $ans); }; // 生成带#[test]属性的成功测试函数 (@success $fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { #[test] impl_test!(@impl $fn_name, $shape, $axis, $ans); }; // 生成带#[test]和#[should_panic]属性的panic测试函数 (@panic $fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { #[test] #[should_panic] impl_test!(@impl $fn_name, $shape, $axis, $ans); }; }
修正方案二:直接在变体中定义带属性的函数
如果测试逻辑简单,可直接在对应宏分支中写出完整的带属性函数:
macro_rules! impl_test { // 普通函数生成 ($fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { fn $fn_name() { let result = calculate_something($shape, $axis); assert_eq!(result, $ans); } }; // 成功测试函数 (@success $fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { #[test] fn $fn_name() { let result = calculate_something($shape, $axis); assert_eq!(result, $ans); } }; // panic测试函数 (@panic $fn_name:ident, $shape:expr, $axis:expr, $ans:expr) => { #[test] #[should_panic] fn $fn_name() { calculate_something($shape, $axis); } }; }
使用示例
// 生成普通函数 impl_test!(normal_test, [2, 3], 0, 2); // 生成成功测试函数 impl_test!(@success success_test, [3, 4], 1, 4); // 生成panic测试函数 impl_test!(@panic panic_test, [1], 1, 0);
内容的提问来源于stack exchange,提问作者musako
相关产品推荐
相关产品推荐

