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

Crystal语言:如何填充数组以包含项目指定包中文件定义的所有模块?

How to collect all modules from a specific package into an array in Crystal?

嘿,这个需求完全可以实现!Crystal的反射API和宏系统刚好能帮你轻松搞定,不用像伪代码那样手动遍历文件判断——咱们用更贴合Crystal风格的方式来做:

方法一:运行时反射(灵活通用)

这种方式适合在程序运行时动态收集所有已加载的、属于指定包的模块,步骤很简单:

  1. 先加载指定包下的所有文件
    假设你的包目录是src/my_package,先递归加载该目录下的所有.cr文件:

    # 递归加载指定包下的所有文件
    Dir["src/my_package/**/*.cr"].each do |file_path|
      require file_path
    end
    
  2. 遍历已加载的模块并过滤
    用ObjectSpace遍历所有已加载的Module实例,然后根据命名空间过滤出属于目标包的模块:

    collected_modules = [] of Module
    
    # 遍历所有已加载的模块
    ObjectSpace.each(Module) do |mod|
      # 判断模块是否属于目标包的命名空间(这里假设包的根模块是MyPackage)
      mod_name = mod.name
      if mod_name == "MyPackage" || mod_name.starts_with?("MyPackage::")
        collected_modules << mod
      end
    end
    
    # 验证结果
    collected_modules.each do |mod|
      puts "Found module: #{mod.name}"
    end
    

方法二:编译时宏(高效可靠)

如果你的包结构是标准的命名空间嵌套(比如所有子模块都直接或间接嵌套在根MyPackage模块下),用编译时宏会更高效——在编译阶段就完成模块收集,不需要运行时遍历:

# 假设你的根模块是MyPackage
module MyPackage
  # 定义一个宏来递归收集所有嵌套模块
  macro collect_all_modules
    {%
      modules = [] of String
      # 递归遍历所有嵌套的模块
      def collect_nested(mod)
        mod.nested_classes.each do |klass|
          if klass.type == "module"
            modules << klass.name
            collect_nested(klass)
          end
        end
      end
      collect_nested(@type)
    %}
    # 返回模块实例的数组
    [{% modules.map { |name| {{name.id}} }.join(", ") %}]
  end
end

# 使用宏获取模块数组
modules = MyPackage.collect_all_modules

# 输出结果
modules.each { |mod| puts "Collected module: #{mod.name}" }

注意事项

  • 不管用哪种方法,都要确保目标包的文件已经被正确require,否则无法收集到未加载的模块
  • 宏方式更适合结构固定的包,运行时反射则更灵活,适合动态加载场景
  • 伪代码里的“判断文件是否是模块文件”其实没必要,因为Crystal加载文件后,模块会自动注册到系统中,直接通过反射获取更准确

内容的提问来源于stack exchange,提问作者Mead

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:05:39