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

Mar*_*tix 37 elixir

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

class MyClass
  MY_FAVORITE_NUMBER = 13
end
Run Code Online (Sandbox Code Playgroud)

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

AbM*_*AbM 45

您可以在前面添加变量名称@:

defmodule MyModule do
  @my_favorite_number 13
end
Run Code Online (Sandbox Code Playgroud)

这是文档

  • "Getter方法"?不要考虑OO.说真的 - 它会让你在FP中得出糟糕的结论. (8认同)
  • 但是无法从模块外部访问@my_favorite_number (4认同)
  • 我根本不称它为"方法".我称之为一个返回值的函数.一种方法具有类的隐含范围; 函数没有这样的隐含范围.方法可以访问默认情况下存在于类中的任何类变量.函数无法访问未在函数中传入或定义的值.改变你的想法. (3认同)
  • @lfx_cool 正确。如果你想从模块外部访问它,你可以定义一个返回其值的函数:`def my_favorite_number, do: @my_favorite_number` (2认同)
  • 它是一个getter方法,如果我们有快捷方式来做这个,例如attr_reader:my_favorite_number (2认同)
  • @OnorioCatenacci,公平地说,在这种情况下,它具有模块的隐含范围,并没有好多少。对于来自 OO 的人来说,这会让你更加困惑,因为你学习了 FP,你被告知纯函数,然后你得到了这个显然不是纯函数的例子。它不接受任何参数并返回基于模块状态的内容。不过我喜欢 Elixir,我认为副作用很难避免(例如对于 IO),但是模块属性在 Ruby 中带有“@”之类的实例变量使其更加混乱。 (2认同)
  • @MigR 它是纯粹的,没有输入,*总是*相同的输出。 (2认同)

Ale*_*arf 12

环顾 github,我看到有人在使用它,这对我很有吸引力。允许从其他模块访问常量。

ModuleA
  @my_constant 23

  defmacro my_constant, do: @my_constant


ModuleB
  Require ModuleA
  @my_constant ModuleA.my_constant
Run Code Online (Sandbox Code Playgroud)

又是一个简单而引人入胜的灵丹妙药解决方案


Ono*_*cci 9

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

  def wxHORIZONTAL, do: 4
  def wxVERTICAL, do: 8
  def wxBOTH, do: (wxHORIZONTAL ||| wxVERTICAL)
Run Code Online (Sandbox Code Playgroud)

这是来自相同源代码的另一个例子:

 # 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)
Run Code Online (Sandbox Code Playgroud)

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

顺便说一下,如果你很好奇,你可以在这里看到回购.

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

  • 这很酷,但有时我想要一个常量,它是一个计算值,这显然会导致函数记忆的兔子洞 http://stackoverflow.com/questions/35465306/how-to-create-a-global-variable-in-长生不老药模块/35468186#35468186。在需要时了解此信息很有用。 (3认同)

cod*_*hal 8

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

defmodule Example
  @site 'StackOverflow' #defining attribute

  def get_site do
    @site #access attribute
  end 
end
Run Code Online (Sandbox Code Playgroud)

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


sat*_*sat 6

也许您定义了一个常量模块文件,并且可以在其中定义宏,如下所示

defmodule MyApp.Constants do
  defmacro const_a do
    quote do: "A"
  end
end
Run Code Online (Sandbox Code Playgroud)

您可以通过将其导入任何其他模块来使用它

defmodule MyApp.ModuleA do
  import MyApp.Constants

  def get_const_a do
    const_a()
  end 
end
Run Code Online (Sandbox Code Playgroud)

好处还在于,您不会招致任何运行时成本,也不会在匹配情况下使用它

case something do
  const_a() -> do_something
  _ -> do_something_else
end
Run Code Online (Sandbox Code Playgroud)