5

銀行口座を表すレコードを書き込もうとしています:

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

また、残高を常に に制限したいと考えています>= 0。どうすればいいですか?

4

2 に答える 2

7

他の人が指摘したように、型指定は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別のモジュールのコードが「不透明な」型指定を無視して、レコードのbalanceフィールドを置き換えることは完全に可能です(レコードは単なるタプルであるため)。

于 2013-04-08T15:24:18.580 に答える