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

如何在Elixir元编程中为模块动态生成语言模块属性?

动态生成模块属性的实现方案

没错,你猜的完全对——要动态生成@lang_es、@lang_en这类模块属性,确实得借助before_compile宏来完成。模块属性是编译期确定的,而before_compile会在模块编译的最后阶段触发,刚好适合用来完成这类需要在编译时动态注入的操作。

下面是修改后的完整代码,既保留了原有的元编程能力,又实现了动态生成模块属性的需求:

defmodule ElixirMeta.LangLoader do
  @external_resource Path.join(__DIR__, "es.json")
  @external_resource Path.join(__DIR__, "en.json")

  defmacro __using__(_opts) do
    # 注册编译前回调,告诉编译器要执行当前模块的__before_compile__函数
    quote do
      @before_compile unquote(__MODULE__)
    end
  end

  # 编译前回调函数,负责动态生成模块属性和访问函数
  def __before_compile__(env) do
    quote bind_quoted: [env: env] do
      # 遍历语言列表,逐个生成模块属性和访问函数
      for lang <- ["es", "en"] do
        json_path = Path.join([unquote(__DIR__), "#{lang}.json"])
        {:ok, body} = File.read(json_path)
        {:ok, json_data} = Poison.decode(body)

        # 动态设置模块属性:@lang_es、@lang_en
        attr_name = String.to_atom("lang_#{lang}")
        Module.put_attribute(env.module, attr_name, json_data)

        # 可选:生成对应的访问函数,方便外部调用
        def unquote(attr_name)(), do: unquote(Macro.escape(json_data))
      end
    end
  end
end

defmodule ElixirMeta.Lang do
  use ElixirMeta.LangLoader

  # 可以在模块内部直接访问模块属性
  def test_internal_access do
    IO.inspect @lang_es, label: "Spanish Lang Data"
    IO.inspect @lang_en, label: "English Lang Data"
  end
end

关键细节说明:

  1. @before_compile的作用:在__using__里注册这个回调,确保编译器在模块即将完成编译时,执行我们定义的__before_compile__/1函数,这是动态生成模块属性的核心时机。
  2. Module.put_attribute/3:用来动态设置模块属性,相比直接在quote里写@lang_es unquote(data),这个函数更可靠,尤其是在动态生成属性名的场景下。
  3. 编译期固化:和你之前的lang/1函数一样,模块属性的内容会在编译时就嵌入到模块中,后续修改JSON文件需要重新编译模块才能生效。

使用示例:

# 外部访问生成的函数
ElixirMeta.Lang.lang_es()
ElixirMeta.Lang.lang_en()

# 模块内部直接访问模块属性
ElixirMeta.Lang.test_internal_access()

这样就完美实现了你想要的效果:既可以通过@lang_es在模块内部直接访问,也可以通过自动生成的lang_es/0函数对外提供访问能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:12:44