dialyzer: Erlang代码分析器
Erlang是一种“动态”语言,这会带来一个问题,单元测试不足以证明我写的代码是否足够正确。很难发现动态语言类型错用的问题。静态类型语言倒是很容易找到此类错误,但是Erlang是“动态的”。
例如,length/1函数只能处理类型为列表(list)的参数,如果传入的不是列表,比如传入一个atom就会出错,但是程序中这样的代码是能够通过编译的,运气好的话会有一个警告,运气差的话只能在运行时发现出错。例如以下代码能成功的编译,也不会有警告,但是显然代码是有问题的,这个问题只能在运行时(foo函数被调用时)才能发现:
bar(List) ->
abc.
foo() ->
V1 = bar([]),
io:format("length: ~p~n", [length(V1)]). %% 这里V1必须是list才行,但是编译时是没法知道的,只有运行时才会发现这个错误
同样的例子,exit/2函数的第一个参数必须是Pid,如果不是也能顺利通过编译,这样只能在运行时才会被发现
此外,我自己写的函数,比如bar函数,可能业务逻辑决定了传入的参数必须是list,返回的参数也应该是list,如果不是,那调用者肯定错误的使用了此函数。在动态语言中很难做到对参数类型和返回类型的限制。
也就是说,对库的接口的错误理解和错误使用是Erlang这样的动态语言常见问题。为此设计了一套合约语言(contract language),有了合约(contract),dialyzer能够很容易的检测到误用的接口
有两种建立合约的方式,一种是在注释里使用@spec这样的annotation,另一种是spec声明
例如规定bar函数只能接收atom或整数,只能返回atom的list:
-type bar_thing() :: atom() | integer(). %% 类型声明:定义bar函数能接收的参数类型
-type ret_thing() :: [atom()]. %% 类型声明:定义bar函数的返回类型
-spec bar(bar_thing()) -> ret_thing(). %% 函数合约:bar函数的参数和返回值
或者
-spec bar(Arg::atom()|integer()) -> [atom()].
另一种是使用annotation的方式,(注意注释中spec要以点号结束annotation,不然无效):
%% @spec bar(Arg::atom()|integer()) -> [atom()].
正如注释一样,annotation不会影响编译。
不过,违反了合约(contact)依然能顺利编译通过,但是我们现在就可以通过dialyzer工具分析源代码找出所有违反合约的代码
dialyzer --src -c test1.erl
可以一次分析工程中的所有文件
dialyzer --src -I ./include -c *.erl
但是可能会有太多的警告信息了,也可以一个文件一个文件的分析,处理起来容易一点
注1:使用dialyzer工具前需要先构建plt:
dialyzer --build_plt -r $OTP_HOME/lib/kernel-2.12.4/ebin\
$OTP_HOME/lib/stdlib-1.15.4/ebin\
$OTP_HOME/lib/mnesia-4.4.5/ebin (或者其它更多的模块)
这一过程耗时很长(大概5分多钟),成功后会在我的home目录下创建一个叫.dialyzer_plt的文件
注2:有个万能类型any()可以代表任意的数据类型;
注3:可以将多个文件中用到的类型(比如pos())集中到一个erl文件中(比如m.erl),通过m:pos()使用该类型;或者将该类型集中到头文件hrl中,使用时包含进来。
注4:typer工具可以列出所有声明的合约
总结:
可以通过确定某种编程规范以及使用Dialyzer这样的工具分析代码是否正确,克服动态语言的弱点。声明和合约一般不影响编译和运行。所以编译通过不一定代表合约有效,还需要dialyzer工具分析
更详细的介绍见
Gradual Typing of Erlang Programs: A Wrangler Experience
分享到:
相关推荐
rebar3_hankErlang死代码清除器 Scorpio先生说生产率提高了2%,这全是因为我的动机技巧,例如甜甜圈和更多甜甜圈的出现。 (荷马·辛普森一家)建造$ rebar3 compile测试$ rebar3 test使用将插件添加到您的钢筋配置...
Erlang随机数兼容性库 ... 避免运行时生成的模块还具有不向Dialyzer隐藏代码的好处。 使用 首先,我们需要生成并加载模块: {ok, rnd} = rand_compat:init(). 或者,您可以指定生成的模块的名称,如下所示: {ok, s
使Dialyzer开心起来从未如此简单。 猫王诊断 在线显示风格的建议。 不再有同事挑剔的评论! 埃多克 将鼠标悬停在本地或远程功能上以查看其edoc 。 当edocs不可用时,您会非常想念此功能,您将开始编写它们! 导航
该库旨在提供一种简单的方法来管理Erlang应用程序的插件,目前抽象非常简单并且层次很高,但是非常灵活。 用法 只需启动应用程序,此刻只有一个名为plugin_dir配置变量,顾名思义,该变量指定了在何处发现插件。 它...
允许您自动缩进您的Erlang代码 运行Eunit测试(模块的所有测试/单个测试) 运行通用测试(该模块的所有测试) 运行Dialyzer测试(单个模块) 轻松转到项目的任何导出功能 从文本编辑器访问手册页 全部在您的测试...
erlex:将Erlang样式结构和错误消息转换为等效的Elixir
Worker Pool 是一个Erlang进程池,其中的工作进程是Erlang的gen server模式进程。Worker Pool的目标是非常简单: 提供以透明的方式管理一批工作进程并且对分配到池中的任务尽最大努力实现负载均衡。一个 Echo 服务器...
支持的OTP版本如何建造编译: make 构建文档: make edoc 运行测试套件: make tests tests-real tests-unit变为make tests tests-real tests-unit 运行透析仪: make dialyzer 运行猫王: make lint 检查代码覆盖率...
介绍该存储库包含一个用于处理base32和base32hex编码的Erlang模块。建造您可以使用以下方法构建库: make build测试您可以使用以下命令执行测试套件: make dialyzer test您可以使用以下方法生成测试覆盖率: make ...
自动,增量式透析器分析(需要Erlang OTP 20) 根据Dialyzer推断的成功类型自动建议@spec批注 内联报告构建警告和错误(需要Elixir> = 1.7) 代码完成 智能自动关闭代码块 悬停文档查找 转到定义 代码格式化程序...
Dialyxir:混合任务以简化Elixir项目中Dialyzer的使用
长生不老日记 创建并列出日记笔记 :pushpin: 目录 :construction_worker: 安装 确保已安装 。 如果您使用的是Mac,只需运行brew...使用mix credo和mix dialyzer Lint代码 :bug: 问题 随时在存储库中提交带有相应标题
Dialyzex:一个Mix任务,用于使用Dialyzer对Elixir项目进行类型检查
埃克西西基于Elixir语言服务器扩展,用于 。... 它在.elixir_ls/dialyzer_manifest维护一个“清单”文件, .elixir_ls/dialyzer_manifest文件存储分析结果。 您可以使用coc-setting.json的elixirLS.dialyzerWarnO
特征: 将项目构建为Docker容器,如果测试通过,则将其自动推送到dockerhub 在您的项目上运行Dialyzer 缓存构建环境和容器层可加快构建时间。如何在您的项目中进行操作: 将scripts / ci文件夹circle.yml和...
由于Webmachine对于更广泛的Erlang社区的重要性,因此成立了一个新的组织。 请联系以参与。 概述 Webmachine是一个应用程序层,它在mochiweb提供的出色的按位和HTTP语法管理的基础上增加了HTTP语义意识,并提供了...
此命令将创建数据库,进行Dialyzer的前工作(如果项目已安装 ),以及进行其他所有操作。 开发人员友好的设置:装入源代码,以便容器中的更改出现在主机上,反之亦然。 快速重建,因为编写了Dockerfile来帮助Docker...
{ alias , [ { renamed , [ " help " ]}, { cleanall , [ " clean " , " -a " ]}, { testall , [ " do " , " ct, " , " eunit, " , " cover " ]}, { validate , [ " do " , " ct, " , " eunit, " , " dialyzer " ]}...
入门发展历程运行测试mix tests 运行透析器mix dialyzer 生成和查看文档mix docs && open doc/index.html 在本地运行应用mix do deps.get, compile(cd apps/exile_web/assets && npm install)iex -S mix phx....
parallel ([ mix ( " dialyzer " ), mix ( " test " ), mix ( " format --check-formatted " ), mix ( " docs " , env: [ mix_env: " dev " ]) ]) ]), timeout: :timer . minutes ( 10 ))|> report_errors