You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键修正点解释

  1. 移除不必要的插值语法:在rule宏中,直接使用{% rules << declaration %}即可引用外层宏中声明的rules数组,不需要用{{rules}}插值——插值是用来将宏变量展开为最终代码的,而这里我们是在宏上下文里操作变量,不是生成代码。
  2. 修正raise中的条件判断:原代码里的\{{declaration.is_a?(TypeDeclaration)}}是错误的,在宏的条件判断中直接使用declaration.is_a?(TypeDeclaration)即可,因为这是在宏运行时执行的检查,不是生成代码的一部分。
  3. 保持上下文一致性:included宏中声明的rules变量会被其内部定义的rule和finished宏共享,因为它们处于同一个宏展开上下文里,所以每次调用rule都会将规则添加到同一个数组中,finished宏可以遍历这个数组生成对应的代码。

运行效果

当你调用StringRule.finished时,会输出两个TypeDeclaration对象的字符串表示,也就是你定义的min : Int32 = 0和max : Int32 = 255对应的类型声明。

内容的提问来源于stack exchange,提问作者Деревянко Сергей

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 07:57:32