Crystal语言中如何在宏中使用临时变量构建代码
在Crystal宏中使用临时变量存储规则的解决方案
你的问题出在嵌套宏里引用外层变量的语法错误上——你错误地使用了插值语法{{rules}}来引用外层宏中声明的rules数组,导致Crystal将其解析为空数组而非已存在的变量。我们可以通过调整宏的语法来实现你想要的功能:在rule宏中收集所有规则,然后在finished宏中复用它们。
修正后的代码
module Rule macro included {% rules = [] of TypeDeclaration %} macro rule(declaration) raise("Should be TypeDeclaration") unless declaration.is_a?(TypeDeclaration) {% rules << declaration %} end macro finished {% for declaration in rules %} puts {{declaration}} {% end %} end end end class StringRule include Rule rule min : Int32 = 0 rule max : Int32 = 255 end # 测试调用 StringRule.finished
关键修正点解释
- 移除不必要的插值语法:在
rule宏中,直接使用{% rules << declaration %}即可引用外层宏中声明的rules数组,不需要用{{rules}}插值——插值是用来将宏变量展开为最终代码的,而这里我们是在宏上下文里操作变量,不是生成代码。 - 修正
raise中的条件判断:原代码里的\{{declaration.is_a?(TypeDeclaration)}}是错误的,在宏的条件判断中直接使用declaration.is_a?(TypeDeclaration)即可,因为这是在宏运行时执行的检查,不是生成代码的一部分。 - 保持上下文一致性:
included宏中声明的rules变量会被其内部定义的rule和finished宏共享,因为它们处于同一个宏展开上下文里,所以每次调用rule都会将规则添加到同一个数组中,finished宏可以遍历这个数组生成对应的代码。
运行效果
当你调用StringRule.finished时,会输出两个TypeDeclaration对象的字符串表示,也就是你定义的min : Int32 = 0和max : Int32 = 255对应的类型声明。
内容的提问来源于stack exchange,提问作者Деревянко Сергей
相关产品推荐
相关产品推荐

