如何获取 erlang 模块的导出类型?
How do I get the exported types of an erlang module?
我有理由检查模块导出的类型,我立即想到 "right, module_info then" 但惊讶 运行 遇到了一些困难。我发现我可以从我编译的模块中获取导出的类型,但不能从 stdlib 中的模块中获取。
我的(三个)问题是,如何可靠地获取模块的导出类型,为什么导出类型在某些模块的模块信息的属性位中,以及为什么某些模块而不是其他模块?
我发现如果我构建这个模块:
-module(foo).
-export([bar/0]).
-export_types([baz/0]).
bar() -> bat .
然后使用 foo:module_info/0, 我得到这个:
[{exports,[{bar,0},{module_info,0},{module_info,1}]},
{imports,[]},
{attributes,[{vsn,[108921085595958308709649797749441408863]},
{export_types,[{baz,0}]}]},
{compile,[{options,[{outdir,"/tmp"}]},
{version,"5.0.1"},
{time,{2015,10,22,10,38,8}},
{source,"/tmp/foo.erl"}]}]
太好了,隐藏在 'attributes' 中的是 'export_types'。为什么这是我不太确定的属性,但是......无论如何......
我现在知道这行得通了:
4> lists:keyfind(export_types, 1, foo:module_info(attributes)).
{export_types,[{baz,0}]}
太棒了。所以,我现在知道这会起作用:
5> lists:keyfind(export_types, 1, ets:module_info(attributes)).
false
啊……没有。
我当然知道有导出类型,如果文档不够好,ets 来源显示:
-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).
事实上,ets 模块的导出类型信息似乎并不在模块信息中的任何位置:
6> rp(ets:module_info()).
[{exports,[{match_spec_run,2},
{repair_continuation,2},
{fun2ms,1},
{foldl,3},
{foldr,3},
{from_dets,2},
{to_dets,2},
{test_ms,2},
{init_table,2},
{tab2file,2},
{tab2file,3},
{file2tab,1},
{file2tab,2},
{tabfile_info,1},
{table,1},
{table,2},
{i,0},
{i,1},
{i,2},
{i,3},
{module_info,0},
{module_info,1},
{tab2list,1},
{match_delete,2},
{filter,3},
{setopts,2},
{give_away,3},
{update_element,3},
{match_spec_run_r,3},
{match_spec_compile,1},
{select_delete,2},
{select_reverse,3},
{select_reverse,2},
{select_reverse,1},
{select_count,2},
{select,3},
{select,2},
{select,1},
{update_counter,3},
{slot,2},
{safe_fixtable,2},
{rename,2},
{insert_new,2},
{insert,2},
{prev,2},
{next,2},
{member,2},
{match_object,3},
{match_object,2},
{match_object,1},
{match,3},
{match,2},
{match,1},
{last,1},
{info,2},
{info,1},
{lookup_element,3},
{lookup,2},
{is_compiled_ms,1},
{first,1},
{delete_object,2},
{delete_all_objects,1},
{delete,2},
{delete,1},
{new,2},
{all,0}]},
{imports,[]},
{attributes,[{vsn,[310474638056108355984984900680115120081]}]},
{compile,[{options,[{outdir,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../ebin"},
{i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../include"},
{i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../../kernel/include"},
warnings_as_errors,debug_info]},
{version,"5.0.1"},
{time,{2014,7,25,16,54,59}},
{source,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/ets.erl"}]}]
ok
我现在把事情做到了极致 运行 这个,将输出记录到一个文件中:
rp(beam_disasm:file("/usr/lib/erlang/lib/stdlib-2.1/ebin/ets.beam")).
并不是说我不认为这很荒谬...但无论如何,它大约有 5,000 行输出,但我在任何地方都找不到字符串 "tid".
的实例
在 Erlang 18 之前,此信息不容易获得。
Dialyzer,例如,从模块的核心 Erlang 版本的抽象语法树中提取它(参见 dialyzer_utils:get_record_and_type_info/1
被 dialyzer_analysis_callgraph:compile_byte/5
使用)
关于这部分:
why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others?
这是因为您的模块中的定义错误。该属性应该是 -export_type
,而不是 -export_types
。如果您使用正确的类型(并定义 baz/0
类型并在某处使用它以便模块编译),导出的类型......正如预期的那样消失。
我有理由检查模块导出的类型,我立即想到 "right, module_info then" 但惊讶 运行 遇到了一些困难。我发现我可以从我编译的模块中获取导出的类型,但不能从 stdlib 中的模块中获取。
我的(三个)问题是,如何可靠地获取模块的导出类型,为什么导出类型在某些模块的模块信息的属性位中,以及为什么某些模块而不是其他模块?
我发现如果我构建这个模块:
-module(foo).
-export([bar/0]).
-export_types([baz/0]).
bar() -> bat .
然后使用 foo:module_info/0, 我得到这个:
[{exports,[{bar,0},{module_info,0},{module_info,1}]},
{imports,[]},
{attributes,[{vsn,[108921085595958308709649797749441408863]},
{export_types,[{baz,0}]}]},
{compile,[{options,[{outdir,"/tmp"}]},
{version,"5.0.1"},
{time,{2015,10,22,10,38,8}},
{source,"/tmp/foo.erl"}]}]
太好了,隐藏在 'attributes' 中的是 'export_types'。为什么这是我不太确定的属性,但是......无论如何......
我现在知道这行得通了:
4> lists:keyfind(export_types, 1, foo:module_info(attributes)).
{export_types,[{baz,0}]}
太棒了。所以,我现在知道这会起作用:
5> lists:keyfind(export_types, 1, ets:module_info(attributes)).
false
啊……没有。
我当然知道有导出类型,如果文档不够好,ets 来源显示:
-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).
事实上,ets 模块的导出类型信息似乎并不在模块信息中的任何位置:
6> rp(ets:module_info()).
[{exports,[{match_spec_run,2},
{repair_continuation,2},
{fun2ms,1},
{foldl,3},
{foldr,3},
{from_dets,2},
{to_dets,2},
{test_ms,2},
{init_table,2},
{tab2file,2},
{tab2file,3},
{file2tab,1},
{file2tab,2},
{tabfile_info,1},
{table,1},
{table,2},
{i,0},
{i,1},
{i,2},
{i,3},
{module_info,0},
{module_info,1},
{tab2list,1},
{match_delete,2},
{filter,3},
{setopts,2},
{give_away,3},
{update_element,3},
{match_spec_run_r,3},
{match_spec_compile,1},
{select_delete,2},
{select_reverse,3},
{select_reverse,2},
{select_reverse,1},
{select_count,2},
{select,3},
{select,2},
{select,1},
{update_counter,3},
{slot,2},
{safe_fixtable,2},
{rename,2},
{insert_new,2},
{insert,2},
{prev,2},
{next,2},
{member,2},
{match_object,3},
{match_object,2},
{match_object,1},
{match,3},
{match,2},
{match,1},
{last,1},
{info,2},
{info,1},
{lookup_element,3},
{lookup,2},
{is_compiled_ms,1},
{first,1},
{delete_object,2},
{delete_all_objects,1},
{delete,2},
{delete,1},
{new,2},
{all,0}]},
{imports,[]},
{attributes,[{vsn,[310474638056108355984984900680115120081]}]},
{compile,[{options,[{outdir,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../ebin"},
{i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../include"},
{i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../../kernel/include"},
warnings_as_errors,debug_info]},
{version,"5.0.1"},
{time,{2014,7,25,16,54,59}},
{source,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/ets.erl"}]}]
ok
我现在把事情做到了极致 运行 这个,将输出记录到一个文件中:
rp(beam_disasm:file("/usr/lib/erlang/lib/stdlib-2.1/ebin/ets.beam")).
并不是说我不认为这很荒谬...但无论如何,它大约有 5,000 行输出,但我在任何地方都找不到字符串 "tid".
的实例在 Erlang 18 之前,此信息不容易获得。
Dialyzer,例如,从模块的核心 Erlang 版本的抽象语法树中提取它(参见 dialyzer_utils:get_record_and_type_info/1
被 dialyzer_analysis_callgraph:compile_byte/5
使用)
关于这部分:
why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others?
这是因为您的模块中的定义错误。该属性应该是 -export_type
,而不是 -export_types
。如果您使用正确的类型(并定义 baz/0
类型并在某处使用它以便模块编译),导出的类型......正如预期的那样消失。