erlang 顺序编程-类型06

本文介绍了Erlang中如何使用Dialyzer进行类型检查。讲解了预定义数据类型如non_neg_integer(), pos_integer(), neg_integer(),以及自定义类型和不透明类型(opaque)的创建。强调了在编写代码时先定义类型的重要性,并指出避免使用-compile(export_all)。还提到了Dialyzer的特点,如详细声明函数参数类型,避免使用匿名变量作为参数,以及首次运行时需要为标准库类型建立缓存。最后,通过示例说明了Dialyzer如何检测函数返回值和参数类型错误,以及如何添加约束条件进行更精确的类型限定。" 119600426,7795838,Maven连接CDH仓库指南,"['大数据开发', 'Hadoop', 'Maven配置', 'Cloudera', '仓库管理']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义新的数据类型并给代码添加类型注解

预定义数据类型

non_neg_integer() 非负的整数

pos_integer()是 一个正整数

neg_integer()是一个负整数

自定义类型

%% 格式
T1 :: A | B | C ...

%% 定义了一共int类型 表示整数
-type int() :: 0,1,-1,2,-2 ......

%% 类似枚举的用法
-type outType :: "DuiZhi","ShunZhi"...

内部定义类型

-spec file:open(FileName,Modes) -> {ok,Handle} | {error,Why} when
    FileName :: string(),
    Modes    :: [Mode],
    Mode     :: read | write | ...
    Handle   :: file_handle(),
    Why      :: error_term().

b模块导入a模块的数据类型

-module(a).
-type rich_text() :: [{font(),char()}].
-type font()      :: integer().

%% 开启其他模块导入权限
-export_type([rich_text/0,font/0]).
-module(b).
...
-spec rich_text_length(a:rich_text()) -> integer().
...

不透明类型opaque ,外部只能只有一个代表它的变量,而不应该知道其具体值。如果使用推到,会被dialyzer检测出来。

-module(a).
-opaque rich_text() :: [{font(),char()}].
-export_type([rich_text/0]).


%% 外部可调用这两个方法,中间用 rich_text的值连接
-export([make_text/1,bounding_box/1]).
-spec make_text(string()) -> rich_text().
-spec bounding_box(rich_text()) -> {Height::integer(),Width::integer()}.
-module(b).
...

do_this() -> 
    X = a:make_text("hello"), %% 调用第一个方法
    {W,H} = a:bounding_box(X),
    [F || {F,_}] <- X.  %% 这一行是不正确的。不能知道内部具体值

    

dialyzer

使用dialyzer的最佳方式是将它用于每一个开发阶段。开始编写一个新模块时,应该首先考虑类型并声明它们,然后再编写代码。

特点:

  • 避免使用-compile(export_all)
  • 为模块导出函数的所有参数提供详细的类型规范。尽量给导出函数的参数设置最严格的限制。
  • 为记录定义里的所有元素提供默认的参数。
  • 把匿名变量用作函数的参数经常会导致结果类型不如你预想得那么精确。

第一次运行dialyzer时,需要为打算使用的所有标准库类型建立缓存。

%% shell
dialyzer

%% 第一个命令会生成erts、stdlib和kernel的PLT
dialyzer --build_plt --apps erts kernel stdlib

内置函数返回值不 对应错误

-module(test1).
-export([f1/0]).

f1() ->
    X = erlang:time(),
    seconds(X).

seconds({_Year,_Month,_Day,Hour,Min,Sec}) -> 
    (Hour * 60 + Min)* 60 + Sec.

dialyzer test1.erl

下面异常说,erlang:time(). 的返回值只有3个 而不是6个。

传入参数异常:它告诉我们list_to_tuple期望的参数是[any()]类型的,而不是{'a','b','c'}

添加约束条件

运算符号默认添加限定number

-module(types1).
-export([f1/1,f2/1,f3/1]).

f1({H,M,S}) -> (H+M*60)*60+S.

f2({H,M,S}) when is_integer(H) -> (H+M*60)*60+S.

f3({H,M,S}) when is_integer(H) -> 
    print(H,M,S),
    (H+M*60)*60+S.

print(H,M,S) ->
    Str = integer_to_list(H) ++ ":" ++ integer_to_list(M) ++ ":" ++ integer_to_list(S),
    io:format("~s",[Str]).

查询f1(),f2(),f3() 的限定

typer types1.erl

%% 运算符默认限定number
-spec f1({number(),number(),number()}) -> number().

%% is_integer() 限定integer
-spec f2({integer(),number(),number()}) -> number().

-spec f3({integer(),integer(),integer()}) -> integer().

%% integer_to_list() 限定integer
-spec print(integer(),integer(),integer()) -> 'ok'.

然后就可以用dialyzer 查看是否书写错误(这个在java里idea直接会报红好么)。书写上和上面合不上就会抛异常

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值