如何为带回调的Elixir函数something/1编写精准Typespec
可以编写更具体的Typespec!
当然可以!虽然回调返回的错误原子是未知的,但我们可以通过自定义类型来让Typespec更具语义性和针对性,而不是直接使用宽泛的atom()或any()。下面分两种场景说明:
场景1:错误原子完全未知(无固定范围)
如果错误原子没有固定的可选集合,我们依然需要用atom()来表示,但可以把相关类型封装成语义化的自定义类型,让Typespec更清晰、易维护:
首先定义描述回调相关逻辑的自定义类型:
# 给错误原因赋予语义化的类型别名 @type error_reason() :: atom() # 明确回调函数的返回结果类型 @type callback_result() :: :ok | {:error, error_reason()} # 定义回调函数本身的类型 @type callback() :: (() -> callback_result())
然后给something/1添加精准的Typespec:
@spec something(callback()) :: callback_result() def something(callback) do case *some condition* do 0 -> :ok 1 -> {:error, :foo} _ -> callback.() end end
这种写法比直接写@spec something(() -> :ok | {:error, atom()}) :: :ok | {:error, atom()}可读性强很多,而且未来如果错误原子的范围能确定,只需要修改error_reason()的定义即可,不用改动函数的spec。
场景2:错误原子有固定范围(可明确限定)
如果之后能明确回调返回的错误原子只能是某些特定值(比如:bar、:baz),那可以直接限定error_reason()的范围,完全摆脱通用的atom()类型:
# 严格限定错误原子的可选值 @type error_reason() :: :foo | :bar | :baz @type callback_result() :: :ok | {:error, error_reason()} @type callback() :: (() -> callback_result()) @spec something(callback()) :: callback_result() def something(callback) do # ... 函数实现代码 end
这种方式的Typespec就非常具体了,完全避免了宽泛类型的使用,还能让静态分析工具(比如Dialyzer)更精准地检查代码逻辑。
内容的提问来源于stack exchange,提问作者NoDisplayName
相关产品推荐
相关产品推荐

