用真实运行验证自定义错误类型:enum + Display + Error + From,沿 source() 逐层打印原因,Debug 保留结构;缺少 Display 时 E0277;Box<dyn Error> 用 downcast_ref 还原具体类型;错误大小拖累 Result(Big 129 字节 → Result 132 字节,装箱后 16 字节)。
下载并真实编译 thiserror 2.0.21 与 anyhow 1.0.104:thiserror 的 derive 展开成 Display/source/From 三个 impl(63 行);anyhow 的 context 链、{:#} 与 {:?} 输出、8 字节体积、downcast;库返回枚举时调用方可 match,返回 anyhow 时只能 downcast。
用真实运行验证 panic:unwrap/expect/数组越界/除零/RefCell 的消息与退出码 101;整数溢出 debug 里 panic 而 release 回绕;unwrap_or 的急切求值;线程 panic 只杀线程、join 返回 Err;panic hook;panic = "abort" 不运行 Drop,被 SIGABRT 终止。
用真实运行验证 catch_unwind:panic 变成 Err(载荷是 &str / String / 任意类型);闭包捕获 &mut 需要 AssertUnwindSafe(否则 E0277);持锁 panic 毒化 Mutex,into_inner 仍可取数据;resume_unwind 不再触发 hook;panic = "abort" 下抓不到;Drop 里再 panic 直接 abort。
用真实运行验证 macro_rules!:模式匹配、$(...),+ 重复、递归宏;用 -Z unpretty=expanded 看展开结果;$x:expr 作为整体但副作用会求值两次;规则不匹配与定义顺序的编译错误;ident/ty/literal/tt 等片段类型。
用真实运行与编译器的 hygiene 打印验证宏卫生性:宏里的 tmp 与调用处的 tmp 是两个变量(#4 对 #0 的语法上下文);宏里引用未传入的调用处变量报 E0425;宏里写死的名字在调用处不可见而传入的 ident 可见;fn 等 item 不卫生;标签也是卫生的。
用一个真实的 proc-macro crate(不依赖 syn)验证过程宏的执行阶段:函数式宏、derive、属性宏的输入 tokens 各是什么;eprintln 只出现在 cargo build 时,运行 app 时没有宏在执行;宏运行次数日志 3 → 3(没改动)→ 6(改了使用者);proc-macro crate 只能导出宏函数。
真实下载 syn 2 + quote 1 写一个 derive(FieldNames):解析 DeriveInput、用 split_for_impl 处理泛型、quote! 生成 impl;编译器展开的代码;syn::Error 指出错误位置(enum 与元组 struct);2000 个 struct 上有无 derive 的编译时间 0.28 s 对 0.53 s。
真实写三个属性宏:#[timed] 用 ItemFn 包装函数体(展开后原体进闭包,返回值不变)、#[route("GET", "/users")] 解析参数并保留原函数加生成常量、#[vanish] 返回空令函数消失(E0425);参数写错时 syn 错误精确指位置;放在 struct 上报 expected `fn`。
真实写三个函数式过程宏:fib!(30) 在编译期算出 832040 并展开成字面量;hashmap!{ k => v } 用 syn 解析自定义语法;embed! 在编译期读文件,但改文件后 cargo 不重新编译(陈旧值),碰一下 main.rs 才更新;错误用 syn::Error 带位置。
用真实运行验证 dbg!:输出到 stderr,格式为 [文件:行:列] 表达式 = 值,并原样返回值;多个参数返回元组,无参数只打印位置;dbg!(v) 会移动 v(E0382);release 构建同样输出;展开是 match tmp 只求值一次;用 {:#?} 美化。
用真实编译验证编译期断言:const _: () = assert!(...) 条件为假时 E0080: evaluation panicked,消息就是自定义字符串;通过时汇编与无断言逐行相同;泛型关联常量与 inline const 块在实例化时才失败,note 指出 instantiating 哪个实例;数组长度下溢技巧也能拦截但消息不可读。