选择any()
一个让 Dialyzer 接受 ETS 匹配模式的好解决方案吗?
Dialyzer 和 match 规格不能很好地配合使用,并且似乎没有标准的解决方案:
- http://erlang.org/pipermail/erlang-questions/2012-June/067581.html
- https://bugs.erlang.org/browse/ERL-892
这是我正在考虑的解决方案的完整示例。如果matcher('_')
在最后一行更改为“_”,则 Dialyzer 会抱怨记录构造错误,但该matcher/1
功能似乎一切正常:
-module(sample).
-record(rec, {field :: number}).
-export([main/1]).
-type matchvar() :: '$1' | '$2' | '$3' | '$4' | '$5' | '$6' | '$7' | '$8' | '$9' | '$10' | '$11' | '$12' | '$13' | '$14' | '$15' | '$16' | '$17' | '$18' | '$19' | '$20' | '$21' | '$22'.
-spec matcher('_' | matchvar()) -> any().
matcher(X) ->
case node() of
'$ will never match' -> binary_to_term(<<>>);
_ -> X
end.
main(_Args) ->
ets:match('my_table', #rec{field = matcher('$1')}, 1).
这是有效的,因为 Dialyzer 不能静态地判断出不可达的第一个子句matcher/1
是不可达的。由于binary_to_term/1
返回any()
,Dialyzer 推断返回类型matcher/1
为 be any()
。
在使用匹配规范时,这个技巧是让 Dialyzer 开心的好方法吗?“好”是指:
- 运行时成本低
- 几支长枪
- 没有更好(更安全、更快、更符合人体工程学)的方式
我看了看它的实现node()
并认为它只是一个指针取消引用,所以成本应该很低。并且 '$ will never match' 真的永远不会匹配,因为node()
总是返回一个带有 an @
in it的原子。但必须有更好的方法。
这里确实有两个问题,我结合起来避免了XY 问题:
- 上面的技术是让 Dialyzer 将某些东西视为 的好方法
any()
吗? - 将 Dialyzer 视为处理
matcher('_')
匹配any()
规范的良好解决方案吗?