Elixir中构建枚举类型的最佳实践有哪些?
Elixir枚举类型实现最佳实践推荐
以下是满足不可篡改、支持整数关联、适配对外API和数值计算场景的可行方案:
方案1:模块封装常量+显式转换函数(通用场景首选)
将枚举映射关系封装在模块内部作为编译期常量,完全规避外部修改风险,同时提供标准化的取值、校验接口:
defmodule IceCreamFlavor do @moduledoc "冰淇淋口味枚举,内部映射不可外部修改" # 编译期固定的枚举-整数映射,外部无法篡改 @value_map %{ vanilla: 0, chocolate: 1, peanut_butter: 2 } @valid_values Map.keys(@value_map) @reverse_map Map.new(Enum.map(@value_map, fn {k, v} -> {v, k} end)) @doc "校验输入是否为合法枚举项" def valid?(flavor), do: flavor in @valid_values @doc "枚举转对应整数,非法输入直接抛出参数错误" def to_int(flavor) when flavor in @valid_values, do: @value_map[flavor] @doc "可选:整数反向转换为枚举atom" def from_int(int) when int in Map.values(@value_map), do: @reverse_map[int] end
使用方式适配你提到的两类场景:
- 对外API参数校验:调用
IceCreamFlavor.valid?(param)即可快速判断入参合法性,非法值直接返回参数错误 - 数值计算场景:调用
IceCreamFlavor.to_int(flavor)获取固定整数参与计算即可
针对时间单位转换这类计算密集的枚举场景可以简化封装:
defmodule DurationType do @value_map %{ milliseconds: 1, seconds: 1000, minutes: 60_000, hours: 3_600_000 } @valid_values Map.keys(@value_map) def to_milliseconds(value, type) when type in @valid_values do value * @value_map[type] end end # 用法示例:5分钟转毫秒 milliseconds = DurationType.to_milliseconds(5, :minutes) # 返回300000
方案2:Ecto.Enum(数据库交互场景)
如果项目使用Ecto做数据库持久化,可以直接使用官方提供的Ecto.Enum类型,自动完成atom和数据库整数字段的双向转换,同时内置参数校验:
schema "ice_creams" do field :flavor, Ecto.Enum, values: [vanilla: 0, chocolate: 1, peanut_butter: 2] end
业务代码中直接用atom操作即可,不需要手动处理整数映射。
方案3:结合类型声明的类型安全枚举(复杂API场景)
如果需要静态校验能力,可以补充类型规范,配合Dialyzer可以在编译期发现非法传参问题:
defmodule IceCreamFlavor do @type t :: :vanilla | :chocolate | :peanut_butter # 其他转换逻辑和方案1一致 end # API函数参数声明枚举类型,静态检查阶段即可发现非法传参 @spec add_kepler_contribution(IceCreamFlavor.t(), float(), list(float())) :: :ok def add_kepler_contribution(type, gm, p_dot) do int_val = IceCreamFlavor.to_int(type) # 后续业务逻辑 end
内容的提问来源于stack exchange,提问作者cppProgrammer
相关产品推荐
相关产品推荐

