如何在Elixir模块中定义常量?

时间:2015-11-22 04:17:30

标签: elixir

在Ruby中,如果一个人在类中定义常量,他们会使用全部大写来定义它们。例如:

class MyClass
  MY_FAVORITE_NUMBER = 13
end

你如何在Elixir中这样做?如果不存在这样的等价物,你如何解决Elixir中魔法数字的问题?

6 个答案:

答案 0 :(得分:43)

您可以使用@

添加变量名称
defmodule MyModule do
  @my_favorite_number 13
end

以下是docs

答案 1 :(得分:7)

Elixir模块可以具有关联的元数据。元数据中的每个项称为属性,并通过其名称访问。您可以使用index.php在模块内定义它。并以@name value

的形式访问
@name

记住这只适用于模块的顶层,你不能在函数定义中设置模块属性。

答案 2 :(得分:7)

定义常量的另一种方法是我使用wxErlang头文件。也就是说,您可以简单地定义一个单行函数,为您返回常量值。像这样:

  def wxHORIZONTAL, do: 4
  def wxVERTICAL, do: 8
  def wxBOTH, do: (wxHORIZONTAL ||| wxVERTICAL)

以及来自相同源代码的另一个示例:

 # From "defs.h": wxDirection
  def wxLEFT, do: 16
  def wxRIGHT, do: 32
  def wxUP, do: 64
  def wxDOWN, do: 128
  def wxTOP, do: wxUP
  def wxBOTTOM, do: wxDOWN
  def wxNORTH, do: wxUP
  def wxSOUTH, do: wxDOWN
  def wxWEST, do: wxLEFT
  def wxEAST, do: wxRIGHT
  def wxALL, do: (wxUP ||| wxDOWN ||| wxRIGHT ||| wxLEFT)

正如您所看到的那样,根据另一个常量定义常量会更容易一些。当我想要在不同模块中使用这些常量时,我​​需要做的就是在模块顶部的require WxConstants。这样可以更容易地在一个地方定义一个常量并在其他几个地方使用它 - 对DRY有很大的帮助。

顺便说一句,如果您有好奇心,可以看到回购here

正如我所说,为了完整起见,我补充这个答案。

答案 3 :(得分:4)

也许您定义了一个常量模块文件,在其中您可以为此定义宏

defmodule MyApp.ModuleA do
  import MyApp.Constants

  def get_const_a do
    const_a()
  end 
end

您可以通过将其导入任何其他模块

来使用它
case something do
  const_a() -> do_something
  _ -> do_something_else
end

这样做的好处是,您不会产生任何运行时成本以及在大小写匹配时使用它的优势

{{1}}

答案 4 :(得分:2)

环顾github,我发现这很吸引我。允许从其他模块访问该常量。

ModuleA
  @my_constant 23

  defmacro my_constant, do: @my_constant


ModuleB
  Require ModuleA
  @my_constant ModuleA.my_constant

又简单又引人入胜的lix剂溶液

答案 5 :(得分:1)

我想补充一下我是如何开始做常量的,这与@Onorio Catenacci的答案类似,但使用了引用:

defmodule IbGib.Constants do

  @doc """
  Use this with `use IbGib.Constants, :ib_gib`
  """
  def ib_gib do
    quote do
      defp delim, do: "^"
      defp min_id_length, do: 1
      # etc...
    end
  end

  @doc """
  Use this with `use IbGib.Constants, :error_msgs`
  """
  def error_msgs do
    quote do
      defp emsg_invalid_relations do
        "Something about the rel8ns is invalid. :/"
      end
      # etc...
    end
  end

  @doc """
  When used, dispatch to the appropriate controller/view/etc.
  """
  defmacro __using__(which) when is_atom(which) do
    apply(__MODULE__, which, [])
  end
end

然后你在模块的顶部使用它,你想要使用它们:

use IbGib.Constants, :ib_gib # < specifies only the ib_gib constants
use IbGib.Constants, :error_msgs

# ... then in some function
Logger.error emsg_invalid_relations

我知道Phoenix如何导入/使用MyApp.Web的子句。我离Elixir专家不远,但是使用这种方法你可以导入你想要的那些常量,你不需要在它们前面添加任何命名空间/范围。这样,您可以轻松地选择各个常量组。

使用直接函数(我认为)你必须将它们分解为多个模块,然后导入模块。

我不知道这个vs直接模块函数的优化后果,但我认为它非常整洁 - 尤其是在Elixir中导入“导入”东西的各种方法之间的练习(import,{{1 }},usealias作为来自其他语言的初学者非常混乱,这是一个requireusing语句。

编辑:我已将常量import声明更改为def。这是因为当常量文件有多个模块defp时,存在模糊性冲突。将它们更改为私有范围的函数可以避免这种冲突。因此每个模块都有自己的同一常量的“私有副本”。