Erlang记录了类型和值限制以及默认值

2rs*_*2ts 5 erlang types records default-value restrictions

我正在尝试写一个代表银行帐户的记录:

-record(account, {  name :: atom(),
                    type :: atom(),
                    balance = 0 :: integer()  }).
Run Code Online (Sandbox Code Playgroud)

我也想限制平衡>= 0.我该怎么做呢?

lms*_*fan 6

类似的东西balance = 0 :: 0 | pos_integer()可以做到这一点.

编辑不确定它是否存在,但non_neg_integer()会更好:

balance = 0 :: non_neg_integer()
Run Code Online (Sandbox Code Playgroud)

  • 请注意,正如Robert Virding所说,这只是读者,文档或工具的信息.它不会阻止平衡为负或其他任何东西(如原子).如果它在您的代码中很重要,那么在使用它和/或修改天平之前,必须使用像is_integer(B)这样的保护,并且还要使用B> = 0. (2认同)

Mar*_*all 6

正如其他人所指出的,类型规范仅仅是输入到分析工具,如适当透析器.如果您需要强制执行不变量balance >= 0,则应该封装帐户类型,只有尊重不变量的函数才能访问:

-module(account).

-record(account, { name :: atom(),
                   type :: atom(),
                   balance = 0 :: non_neg_integer() }).

%% Declares a type whose structure should not be visible externally.
-opaque account() :: #account{}.
%% Exports the type, making it available to other modules as 'account:account()'.
-export_type([account/0]).

%% Account constructor. Used by other modules to create accounts.
-spec new(atom(), atom(), non_neg_integer()) -> account().
new(Name, Type, InitialBalance) ->
    A = #account{name=Name, type=Type},
    set_balance(A, InitialBalance).

%% Safe setter - checks the balance invariant
-spec set_balance(account(), non_neg_integer()) -> account().
set_balance(Account, Balance) when is_integer(Balance) andalso Balance >= 0 ->
    Account#account{balance=Balance};
set_balance(_, _) -> error(badarg). % Bad balance
Run Code Online (Sandbox Code Playgroud)

请注意,它类似于具有面向对象语言(如Java或C++)中的私有字段的类.通过限制对"受信任"构造函数和访问器的访问,强制执行不变量.

此解决方案不提供针对该字段的恶意修改的保护balance.另一个模块中的代码完全可以忽略"opaque"类型规范并替换记录中的balance字段(因为记录只是元组).