我正在编写一个自定义的 Ecto 类型,其行为类似于枚举类型。我有一个原子 => 整数的关键字列表。
我意识到我可以使用 Elixir 模块(实际上只是原子)作为我的 key ,而不是常规原子。但我不确定这是否是一种糟糕的形式。
对我来说,使用模块 1) 看起来更重要、更明显,可接受的值在范围内受到限制,2) 提供了一些正确代码建议的机会。
由于它们“只是原子”,我不认为这样做会比其他方式带来更多的性能损失?同时,传递规则原子对于 Elixir 来说似乎更自然一些?
我不太担心错误的原子被插入到数据库中,因为我使用任一方法检查强制转换/转储,这更多是一个风格问题。
这里的最佳实践是什么?你会做什么?
模块作为 key
defmodule App.Background.BackgroundJob.Pool do
# you could probably macro this if you hated the look of the syntax
defmodule Local do end
defmodule Remote do end
@behaviour Ecto.Type
@pools [{Local, 0}, {Remote, 1}]
# cast, load, etc...
end
job = %{
pool: BackgroundJob.Pool.Local,
# ...
}
原子作为 key
defmodule App.Background.BackgroundJob.Pool do
@behaviour Ecto.Type
@pools [{:local, 0}, {:remote, 1}]
# possibly have these functions
def local, do: :local
def remote, do: :remote
# cast, load, etc...
end
job = %{
pool: BackgroundJob.Pool.local,
# ...
}
# or
job = %{
pool: :local,
# ...
}
最佳答案
没有 Elixir 。我经常使用 Elixir 模块作为键,但只有当它们成为一个模块有意义时(附加功能、函数等等)。
这里使用模块只是为了节省几次击键。这对我来说看起来具有误导性和唐突性。为了避免代码重复并通过 DRY,人们可以简单地将模块转换为结构:
defmodule App.Background.BackgroundJob.Pool do
@enum [local: 0, remote: 1]
defstruct @enum
@behaviour Ecto.Type
@pools @enum
# cast, load, etc...
end
job = %{
pool: BackgroundJob.Pool.local,
# ...
}
或任何其他提供更清晰的方式,例如宏:
defmodule Enum do
defmacro __using__(enum) do
enum
|> Enum.with_index()
|> Enum.map(fn {name, idx} ->
quote location: :keep do
def unquote(name)(), do: unquote(idx)
end
end)
end
end
use Enum, [:local, :remote]
job = %{
pool: BackgroundJob.Pool.local,
# ...
}
关于elixir - 使用模块作为常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53367268/