5

必要なテーブルが既に作成されていることを確認する関数を作成しようとしています。サンプルは次のとおりです。

ensure_table_exists(Table, MnesiaTables, Nodes) ->
case lists:member(Table, MnesiaTables) of
    true ->
        throw({error, db_might_have_already_been_created});
    false ->
        mnesia:create_table(Table, [{disc_copies, Nodes},
                {attributes, record_info(fields, Table)}]), 
        ok  
end.

問題は、コンパイル時にエラーが発生することです: illegal record info. コンパイル時に record_info が解決されるか、record info の 2 番目の引数が実際にはソース コードから取得できるレコードでなければならないのでしょうか?

4

3 に答える 3

5

はい、を含むすべてのレコード関連のものrecord_info/2はコンパイル時に解決されます。これは、レコード名とフィールド名がコンパイル時に認識されている必要があることを意味します。これがコンパイラエラーの理由です。

あなたがしていることがより具体的なエラーを示しているという点で、あなたの関数は本当に防御的すぎるとは思いません。あなたが戻っ {error, ...}た場合、それは別の問題になるでしょう。

最後のポイントは、例外を発生させる場合は、を使用するのではなく、を使用する必要があるということthrow/1ですerlang:error/1throw非ローカルリターン(でキャッチcatch)をerlang:error目的としていますが、例外を発生させることを目的としています。多くの場合、結果は同じですが、実際のエラー値は誤解を招く可能性があります(nocatch)。意図を明確に示すことができる方が常に優れています。この場合は、エラーのシグナルです。

PSはい、それもエラー/終了をキャッチすることを私は知っていますcatchこれは意図的なものでした。完璧な世界では、おそらくcatchスローとtryエラー/終了のみをキャッチする必要があります。

于 2010-09-10T17:42:51.160 に答える
3

残念ながら、record_info は関数のように見えても実際には関数ではありません。

以下をテストすることで確認できます。ファイルを作成します。

 -module(something).
 -record(a, {}).

Erlang シェルを起動します。

 > rr(something).
 [a]
 > record_info(fields, a).
 []
 > A = a.
 > record_info(fields, A).
 * 2: illegal record info

したがって、record_info 部分にはマクロまたは特殊な関数を使用することをお勧めします。

元の質問に答えるために。次のようなものを使用します。

 tables() ->
   [?TABLE_MACRO(tablename),
    ?TABLE_MACRO(tablename2),
    ...].

TABLE_MACRO は次のようなものです。

 -define(TABLE_MACRO(Table), fun() ->
      mnesia:create_table(Table, [{disc_copies, Nodes},
               {attributes, record_info(fields, Table)}])
      end).

次に、以下のような関数を使用します。

 [case CreateTable of
   {aborted, {already_exists, _}} -> ok;
   {atomic, ok} -> ok
  end || CreateTable <- tables()].

うん!かなりクリーンアップできますが、うまくいけば、一般的な考え方を理解できます。

  • 変数の代わりにマクロを使用します。
  • {atomic, ok} と {aborted, {already_exists, _TableName}} の両方で一致
于 2010-09-13T15:28:54.407 に答える
0

Ulf Wiger のexpeccsを参照してください。

説明から読む:

モジュールは、レコードのエクスポートを可能にする解析変換です。変換は、モジュール間のコンパイル時の依存関係を導入する必要なく、レコードのインスタンス化、検査、および変更のためのアクセサー関数を追加します。

そうは言っても、あなたの機能は私には少し防御的に聞こえます。次のページでは、Erlang で防御的にプログラミングすることがなぜ悪い習慣なのかを説明しています。

http://www.erlang.se/doc/programming_rules.shtml#HDR11

于 2010-09-10T14:01:00.513 に答える