我正在尝试编写代表银行帐户的记录:
-record(account, { name :: atom(),
type :: atom(),
balance = 0 :: integer() }).
我还想将平衡限制为始终>= 0
。我该怎么做呢?
我正在尝试编写代表银行帐户的记录:
-record(account, { name :: atom(),
type :: atom(),
balance = 0 :: integer() }).
我还想将平衡限制为始终>= 0
。我该怎么做呢?
正如其他人所指出的,类型规范仅仅是PropEr和Dialyzer等分析工具的输入。如果您需要强制执行不变量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
请注意,这类似于 Java 或 C++ 等面向对象语言中具有私有字段的类。通过限制对“受信任的”构造函数和访问器的访问,可以强制执行不变量。
此解决方案不提供防止恶意修改balance
字段的保护。另一个模块中的代码完全有可能忽略“不透明”类型规范并替换记录中的 balance 字段(因为记录只是 tuples)。
类似的东西balance = 0 :: 0 | pos_integer()
可能会奏效。
编辑不确定它是否存在,但non_neg_integer()
会更好:
balance = 0 :: non_neg_integer()