如何在 Elixir 上定义共享常量

KON*_*uke 3 elixir

我可以定义与模块共享的常量吗?

通常,我们使用模块属性作为模块内部的常量。 http://elixir-lang.github.io/getting-started/module-attributes.html#as-constants

如果我想让其他模块可以使用常量,我该怎么做?起初,module 属性仅在 module(1) 内部可用。我知道我可以将函数用作常量(2)。但是如果可能的话,我想通过像 3 这样的专用形式来定义常量。

defmodule Sample do
    # 1. module attribute(available only inside module)
    @private_const_value 1
    # 2. function as constant(possible in any rate)
    def const_value_func, do: 3
    # 3. ideal form(but compile error)
    public_const_value = 2
end

defmodule Client do
    def foo() do
        IO.puts "CONST = #{Sample.@private_const_value}" # compile error
        IO.puts "CONST = #{Sample.const_value_func}"
        IO.puts "CONST = #{Sample.public_const_value}" # compile error
    end
end
Run Code Online (Sandbox Code Playgroud)

后记

我希望常量满足以下要求。

  • 编译时评估
  • 按模块分类(我的意思是常量应该在适当的模块中定义)

Dav*_*man 5

非模块特定的常量通常放在 中config/foo.exs,并由System.get_env/1或访问Application.get_env/2。如果您希望它位于特定模块(而不仅仅是特定应用程序)的下方/内部,原因无法通过为其提供适当的名称并使用上述选项之一来满足...首先,请确保这是准确的,你有一个很好的理由,因为我想不出一个。

如果您仍然想要那个,答案是 (AFAIK) 只是您的选项 2,即函数。如果你想要一个专门的表格,用一个宏来做:

defmacro const([{name, val}]) do
  quote do
    def unquote(name) do: unquote(val)
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以const foo: 87在您需要的任何模块中执行并导入其中const定义的模块。

或者您可以将每个常量定义为宏而不是函数。缺点:你需要require模块。优点:在编译时解析,就像属性一样。尽管没有副作用的 arity 0 函数可能会这样做,但我不确定,但这是一个合理的优化。