2010-09-10 59 views
4

我想有一个函数,确保我需要的表已经创建,如果不创建它。这里的样本:erlang mnesia - 非法记录信息

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在编译时解析或第二个参数记录信息应该实际上是一个可以从源代码中检索的记录?

回答

0

您可能想看看Ulf Wiger's exprecs。从描述

阅读:

The module is a parse transform allowing you to export records. The transform adds accessor functions for instantiating, inspecting and modifying records, without having to introduce compile-time dependencies between modules.

说,你的功能听起来有点防守给我。下页解释了为什么这是一个坏习惯,在二郎防守编程:

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

+0

我知道防守在Erlang编程的坏习惯,但我不明白这是什么必须做我的功能?我只是试图确保我没有创建架构。 – hyperboreean 2010-09-10 14:17:04

3

是的,所有的记录相关东西包括record_info/2在编译时解决。这意味着在编译时必须知道记录和字段名称。这是编译器错误的原因。

我不认为你的功能实在太防守,因为你正在做的是发出更具体的错误信号。如果你想返回{error, ...}这将是另一回事。

最后一点是,如果您的意思是提出异常,则不应使用throw/1,而应使用erlang:error/1throw用于非本地退货(与catch挂钩),而erlang:error用于引发异常。在很多情况下,结果可能相同,但实际误差值可能会引起误解(nocatch)。你可以更清楚地表明你的意图,在这种情况下,这意味着一个错误。

P.S.是的,我知道catch也捕获错误/退出。这是故意的。在一个完美的世界可能catch应该只捕获抛出和try只有错误/退出。

2

不幸的是,即使看起来像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()]. 

Yuck!可以清理很多,但希望你了解一般想法。

  • 宏而不是变量的使用。
  • 同时匹配{原子,OK}和{中止,{ALREADY_EXISTS,_TableName}}