[Erlang开发之路]九、类型的定义与使用 & dialyze

2019-07-18  本文已影响0人  循环不计次

一、指定数据和函数类型

-module(walks).
-export([]).
%定义区
-type point() :: {integer(),integer()}.
-spec plan_route(Start::point(),End::point())-> route().
-type direction() :: east|west|north|south|none.
-type route() :: {go,direction(),point()}.
-type angle() :: Degrees::0..360.
-spec getXDict(integer())->direction().
-spec getYDict(integer())->direction().
-spec getDict(integer(),integer()) - > [direction()].
%---------------
getDict(X,Y)->
    [getXDict(X),getYDict(Y)].
getXDict(P)->
    if
        P=:=0 -> none;
        P>0 -> west;
        P<0 -> east
    end.
getYDict(P)->
    if
        P=:=0 -> none;
        P>0 -> south;
        P<0 -> north
    end.
plan_route(S,E)->
    {Xa,Ya}=S,
    {Xb,Yb}=E,
    {go,getDict(Xa-Xb,Ya-Yb),E}.

我们来拿上面的代码做例子:

看完这个例子你应该可以掌握大部分的类型定义方法了

二、Erlang的类型表示法

1.类型的语法

Type:: any() | none() | pid() | port() | reference() | [] | Atom | binary() | float() | Fun | Integer | [Type] | Tuple | Union | UserDefined

Union:: Type1 | Type2 | ....

Atom:: atom() | Erlang_Atom

Integer:: integer() | Min..Max

Fun:: fun() | fun((...) -> Type)

Tuple:: tuple() | {T1,T2,...,Tn}

以上就包含了所有Erlang的内置类型和语法了,特别说明如下:

2.指定函数的输入和输出类型

编写规范如下:

-spec functionName(T1,T2,..,Tn) -> Tret when
T1 :: Type1,
T2 :: Type2,
...
Tret :: TypeRet.

3.导出类型、本地类型和透明类型

-module(a)
-type rich_text() :: [{front(),char()}].
-type font() :: integer().
-type for_example(integer(),integer()):: [ {Key,Val} ].
-opaque rich_text2() :: [{front(),char()}].
-export_type([rich_text()/0,font()/0,for_example()/2]).

-module(b)
-spec rich_text_length(a:rich_text())->integer().

通过上面两个例子,我们可以了解到一些东西:


a.导出变量类型:
-export_type([type/typeVarNum]).
type是类型,typeVarNum是类型变量的数量,如果你不知道是什么,我们回滚到上面的代码,有一个for_example变量,他有一个Key,和Val 这两个其实是类型的变量,for_example是由元组{Key类型的变量,Val类型的变量}组成的[{Key,Val}]列表


b.使用导入的类型
ModName:TypeName()
这就不多说了


c.不透明类型
什么是不透明类型?就是你在a定义的不透明类型rich_text2(),在b中使用的时候,比如说拿去匹配,编译器会告诉你:抽象违规(abstraction violation),因为别人是不透明的,b不可能会知道rich_text2()的结构是怎样的(虽然你自己知道),所以就会匹配错误。
定义方法:
- opaque typename():: xxxx

三、dialyzer差错分析

1.第一次运行dialyzer

跟着他的提示运行:
dialyzer --build_plt --apps erts kernel stdlib mnesia
就okay了,大概花个两分钟就完成了,这个步骤其实就是生成 erts kernel stdlib mnesia的PLT(持久性查询表)的操作

2.使用dialyzer分析erl源码

在学习类型的定义与使用的时候,我还在想这样定义有什么用呢?直到我开始学习dialyzer才知道:哦,原来是为了检查源代码中有没有错误(错误使用内置函数的返回值,内置函数的错误参数,错误的程序逻辑),这让我想起了我写C++的日子,用着VS2017享受着Intellicode给我自动提醒有没有哪里有错误,反过头来看,erlang好像还没有这么便捷的工具。


回到正题,怎么样使用dialyzer分析源码呢,其实很简单,cmd -> dialyzer ErlSrc
就可以完成这个工作

3.干扰dialyzer的事物

四、typer类型推断

有时候dialyzer生成的错误报告,你会看的一头雾水,这个时候你就需要用typer来看看系统是怎么理解你的变量类型的,他会打印出你所有的函数类型定义-spec xxx

上一篇 下一篇

猜你喜欢

热点阅读