使用模块作为常量
Using modules as constants
我正在编写一个行为类似于枚举类型的自定义 Ecto 类型。我有一个原子关键字列表 => 整数。
我意识到我可以为我的密钥使用 Elixir 模块(实际上只是原子),而不是常规原子。不过我不确定这是否形式不佳。
对我来说,使用模块 1) 看起来更重要和明显,可接受的值在范围内受到限制,并且 2) 为正确的代码建议提供了一些机会。
因为它们“只是原子”,我不认为这样做会导致比其他方式更多的性能损失?同时,通过常规原子似乎对 elixir 更自然一些?
我不太担心将错误的原子插入数据库,因为我使用这两种方法检查 cast/dump,这更像是一个风格问题。
此处的最佳做法是什么?你会怎么做?
模块作为键
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,
# ...
}
没有灵丹妙药。我经常使用 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,
# ...
}
我正在编写一个行为类似于枚举类型的自定义 Ecto 类型。我有一个原子关键字列表 => 整数。
我意识到我可以为我的密钥使用 Elixir 模块(实际上只是原子),而不是常规原子。不过我不确定这是否形式不佳。
对我来说,使用模块 1) 看起来更重要和明显,可接受的值在范围内受到限制,并且 2) 为正确的代码建议提供了一些机会。
因为它们“只是原子”,我不认为这样做会导致比其他方式更多的性能损失?同时,通过常规原子似乎对 elixir 更自然一些?
我不太担心将错误的原子插入数据库,因为我使用这两种方法检查 cast/dump,这更像是一个风格问题。
此处的最佳做法是什么?你会怎么做?
模块作为键
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,
# ...
}
没有灵丹妙药。我经常使用 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,
# ...
}