我正在拧紧自定义的Ecto类型,其行为类似于枚举类型。我有一个原子列表关键字=>整数。
我意识到我可以将Elixir模块(实际上只是原子)用作我的键,而不是常规原子。我不确定这是不是很差的形式。
对我来说,使用模块1)看起来更重要,而且很明显可接受的值在范围上受到限制,而模块2)为正确的代码建议提供了一些机会。
由于它们只是“原子”,因此我不认为这样做会带来比我更高的性能损失吗?同时,通过常规原子似乎对长生不老药更自然?
我不太担心将错误的原子插入数据库中,因为我使用这两种方法检查了强制转换/转储,这更多地是一个风格问题。
这里的最佳做法是什么?你会怎么做?
模块密钥
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,
# ...
}
原子键
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,
# ...
}
答案 0 :(得分:2)
没有银弹。我经常使用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,
# ...
}