在 Elixir 中构建枚举有哪些好的做法?
What are some good practices for building enumerations in Elixir?
显然原子是枚举值的最佳选择。但是这些与整数无关或不可转换为整数。
我认为结构可能是可行的方法。下面的代码有效。
defmodule ElixirTesting do
import ExUnit.Assertions
defmodule IceCreamFlavorEnumeration do
defstruct vanilla: 0, chocolate: 1, peanut_butter: 2
end
def test_enumeration do
e = %IceCreamFlavorEnumeration{}
v = e.vanilla
c = e.chocolate
p = e.peanut_butter
assert v < c
assert c < p
end
end
但是,结构的用户可以重新分配整数值。我相信甚至重新分配给非整数值。如果暴露在 API.
中,这是不可接受的
考虑 api 例如 this:
void addKeplerContribution(PositionAngle type, double gm, double[] pDot)
或者在数学意义上使用整数值(转换为毫秒——这是一个虚构的函数):
enum DurationType {
MILLISECONDS = 1,
SECONDS = 1e3,
MINUTES = 60e3,
...
}
void addMilliseconds(DurationType type, double duration_value) {
...
milliseconds = duration_value * (int)type;
...
}
关键字列表可能是替代方法。还有其他建议吗?
我们通常为此使用模式匹配。
@type interval :: :millis | :seconds | :minutes
@spec add_interval(interval(), integer()) :: integer()
def add_interval(:millis, duration) when is_integer(duration),
do: duration
def add_interval(:seconds, duration) when is_integer(duration),
do: duration * 1_000
def add_interval(:minutes, duration) when is_integer(duration),
do: duration * 1_000 * 60
这条路乍一看可能不熟悉,但这是必经之路。您明确禁止调用此函数时将有点未知作为第一个参数,并且您只接受整数作为第二个参数。
显然原子是枚举值的最佳选择。但是这些与整数无关或不可转换为整数。
我认为结构可能是可行的方法。下面的代码有效。
defmodule ElixirTesting do
import ExUnit.Assertions
defmodule IceCreamFlavorEnumeration do
defstruct vanilla: 0, chocolate: 1, peanut_butter: 2
end
def test_enumeration do
e = %IceCreamFlavorEnumeration{}
v = e.vanilla
c = e.chocolate
p = e.peanut_butter
assert v < c
assert c < p
end
end
但是,结构的用户可以重新分配整数值。我相信甚至重新分配给非整数值。如果暴露在 API.
中,这是不可接受的考虑 api 例如 this:
void addKeplerContribution(PositionAngle type, double gm, double[] pDot)
或者在数学意义上使用整数值(转换为毫秒——这是一个虚构的函数):
enum DurationType {
MILLISECONDS = 1,
SECONDS = 1e3,
MINUTES = 60e3,
...
}
void addMilliseconds(DurationType type, double duration_value) {
...
milliseconds = duration_value * (int)type;
...
}
关键字列表可能是替代方法。还有其他建议吗?
我们通常为此使用模式匹配。
@type interval :: :millis | :seconds | :minutes
@spec add_interval(interval(), integer()) :: integer()
def add_interval(:millis, duration) when is_integer(duration),
do: duration
def add_interval(:seconds, duration) when is_integer(duration),
do: duration * 1_000
def add_interval(:minutes, duration) when is_integer(duration),
do: duration * 1_000 * 60
这条路乍一看可能不熟悉,但这是必经之路。您明确禁止调用此函数时将有点未知作为第一个参数,并且您只接受整数作为第二个参数。