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

Crystal如何使用宏在编译时从文件生成代码加载CSV数据

Crystal编译时加载CSV数据为常量实现方案

核心问题原因

Crystal的{{ run <path> }}宏的运行机制是:编译阶段执行指定的Crystal脚本,仅将脚本标准输出的内容作为Crystal源代码片段插入到宏调用的位置,不会直接传递脚本运行时的内存对象。
你最初的脚本直接构造了OpenData::Country数组但没有输出任何内容,所以宏位置等效于没有任何代码,才会触发得到Nil的类型不匹配报错。

正确实现

1. 代码生成脚本(./sources/country_codes.cr)

你修改后的版本逻辑是正确的,补充特殊字符转义处理的优化版如下:

require "csv"

content = File.read "#{__DIR__}/country-codes.csv"
instances = CSV.new(content, headers: true).map do |row|
  # 处理字段内的双引号避免生成的代码出现语法错误
  code = row["CountryCode"].gsub('"', '\\"')
  name = row["CountryName"].gsub('"', '\\"')
  %[Country.new("#{code}", "#{name}")]
end
puts "[#{instances.join(", ")}]"

2. 主代码中加载

module OpenData
  class Country
    def initialize(@code : String, @name : String)
    end
  end

  @@countries : Array(Country) = {{ run "./sources/country_codes.cr" }}
end

编译阶段展开后,宏位置会直接替换为脚本输出的数组字面量,等效于你手动写了:

@@countries : Array(Country) = [Country.new("AD", "Andorra"), Country.new("AE", "United Arab Emirates"), ...]

扩展说明

如果你有大量同类CSV需要处理,可以把代码生成逻辑封装为通用工具,传入CSV路径、类名、字段映射规则即可自动生成对应代码,不用为每个CSV单独写生成脚本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 14:15:03