Erlang Mnesia - информация о незаконных записях - PullRequest
5 голосов
/ 10 сентября 2010

Я пытаюсь создать функцию, которая гарантирует, что нужная мне таблица уже создана, а если нет, то создайте ее. Вот образец:

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. Возможно, придется сделать так, чтобы запись_инфо была разрешена во время компиляции, или чтобы второй аргумент для записи информации фактически был записью, которую можно извлечь из исходного кода?

Ответы [ 3 ]

4 голосов
/ 10 сентября 2010

Да, все относящиеся к записи вещи , включая record_info/2, разрешаются во время компиляции. Это означает, что имена записей и полей должны быть известны во время компиляции. Это является причиной ошибки компилятора.

Я не думаю, что ваша функция действительно слишком оборонительна, потому что то, что вы делаете, сигнализирует о более конкретной ошибке. Другое дело, если бы вы вернули {error, ...}.

И последнее замечание: если вы хотите вызвать исключение, вы не должны использовать throw/1, а вместо этого использовать erlang:error/1. throw предназначен для нелокального возврата (перехвачен catch), а erlang:error предназначен для вызова исключения. Во многих случаях результат может быть таким же, но фактическое значение ошибки может вводить в заблуждение (nocatch). Это всегда лучше, чем яснее вы можете показать свое намерение, которое в этом случае сигнализирует об ошибке.

P.S. Да, я знаю , что catch также ловит ошибки / выходы. Это было преднамеренно. В идеальном мире catch должен ловить только броски, а try только ошибки / выходы.

2 голосов
/ 13 сентября 2010

К сожалению, 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}, так и {прервано, {ready_exists, _TableName}}
0 голосов
/ 10 сентября 2010

Возможно, вы захотите взглянуть на Ульфа Вигера exprecs .

Чтение из описания:

Модульпреобразование синтаксического анализа, позволяющее экспортировать записи.Преобразование добавляет функции доступа для создания экземпляров, проверки и изменения записей без необходимости вводить зависимости времени компиляции между модулями.

Сказал, что ваша функция звучит немного для защиты для меня,На следующей странице объясняется, почему вредно программировать в обороне на эрланге:

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

...