【问题标题】:Erlang records with both type and value restrictions as well as default values具有类型和值限制以及默认值的 Erlang 记录
【发布时间】:2013-03-28 06:38:22
【问题描述】:

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

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

我还想将余额限制为始终为>= 0。我该怎么做?

【问题讨论】:

  • 请注意,虽然您可以将类型声明为非负整数,但这不会在运行时强制执行任何操作,它实际上只是一个注释。您可以将余额字段设置为您选择的任何值和任何类型。
  • @rviding 如何在运行时强制执行此行为(没有函数保护)?或者这种伪静态类型在 Erlang 中不存在?
  • 你不能! Erlang 太动态了,所以语言中不存在静态类型,编译器也不使用这些信息。它仅用于文档和类型检查工具dialyzer。

标签: types erlang default-value records restrictions


【解决方案1】:

balance = 0 :: 0 | pos_integer() 之类的东西可能会奏效。

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

balance = 0 :: non_neg_integer()

【讨论】:

  • 我也不知道它的存在。非常感谢!
  • 请注意,正如 Robert Virding 所说,这只是为读者、文档或工具提供的信息。它不会阻止平衡为负数或其他任何东西(如原子)。如果它在你的代码中很重要,你必须在使用它和/或修改余额之前使用像 is_integer(B) 和 B >= 0 这样的保护。
  • 谢谢@Pascal,我一定会使用这些警卫。 :)
【解决方案2】:

正如其他人所指出的,类型规范仅仅是PropErDialyzer 等分析工具的输入。如果您需要强制执行不变量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 字段的恶意修改的保护。另一个模块中的代码完全有可能忽略“不透明”类型规范并替换记录中的余额字段(自records are just tuples)。

【讨论】:

  • 感谢您的示例和警告!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-09
  • 2022-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多