简体   繁体   English

如何获得erlang模块的导出类型?

[英]How do I get the exported types of an erlang module?

I had cause to check the types exported by a module, and I immediately thought "right, module_info then" but was surprised to run into a few difficulties. 我有理由检查模块导出的类型,我立即想到“正确,然后是module_info”,但惊讶地遇到了一些困难。 I found I can get the exported types from modules I compile, but not from say modules in stdlib. 我发现可以从编译的模块中获取导出的类型,而不能从stdlib中的模块获取导出的类型。

My (three) questions are, how do I reliably get the exported types of a module, why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others? 我的(三个)问题是,如何可靠地获取模块的导出类型?为什么导出的类型在某些模块的模块信息的属性位中显示?为什么某些模块而不是其他模块?

I discovered that if I build this module: 我发现如果我构建此模块:

-module(foo).
-export([bar/0]).
-export_types([baz/0]).
bar() -> bat .

And then use foo:module_info/0, I get this: 然后使用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"}]}]

Great, hidden away in 'attributes' is 'export_types'. 很好,隐藏在“属性”中的是“ export_types”。 Why this is in attributes I'm not quite sure, but... whatever... 为什么我不确定属性的属性,但是...无论如何...

I now know this will work: 我现在知道这可以工作:

4> lists:keyfind(export_types, 1, foo:module_info(attributes)).
{export_types,[{baz,0}]}

Great. 大。 So, I now know this will work: 因此,我现在知道这将起作用:

5> lists:keyfind(export_types, 1, ets:module_info(attributes)).
false

Ah... it doesn't. 啊...不是。

I know there are exported types of course, if the documentation isn't good enough the ets source shows: 我知道当然有导出类型,如果文档不够好,ets源会显示:

-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).

In fact the exported type information for the ets module doesn't seem to be anywhere in the module info: 实际上,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

I took things to extremes now and ran this, logging the output to a file: 我现在把一切都极端化了,然后运行它,将输出记录到文件中:

rp(beam_disasm:file("/usr/lib/erlang/lib/stdlib-2.1/ebin/ets.beam")).

Not that I don't consider this absurd... but anyway, it's about 5,000 lines of output, but nowhere do I find an instance of the string "tid". 并不是说我不认为这很荒谬……但是无论如何,它大约有5,000行的输出,但是我在哪里都找不到字符串“ tid”的实例。

Up to Erlang 18 this information is not easily available. 在Erlang 18之前,此信息不容易获得。

Dialyzer, for example, extracts it from the abstract syntax tree of the core Erlang version of a module (see eg dialyzer_utils:get_record_and_type_info/1 used by eg dialyzer_analysis_callgraph:compile_byte/5 ) 例如,Dialyzer从模块的核心Erlang版本的抽象语法树中提取它(请参阅例如dialyzer_utils:get_record_and_type_info/1 dialyzer_analysis_callgraph:compile_byte/5使用的dialyzer_utils:get_record_and_type_info/1

Regarding this part: 关于这部分:

why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others? 为什么某些模块的模块信息的属性位中的导出类型是?为什么某些模块而不是其他模块?

this is due to a bad definition in your module. 这是由于模块中的定义错误。 The attribute should be -export_type , not -export_types . 该属性应该是-export_type ,而不是-export_types If you use the correct one (and define the baz/0 type and use it somewhere so that the module compiles), the exported types... vanish, as is expected. 如果使用正确的类型(并定义baz/0类型并在某个地方使用它以便模块进行编译),则导出的类型将消失,正如预期的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM