【问题标题】:erlang mnesia - illegal record infoerlang mnesia - 非法记录信息
【发布时间】:2010-09-13 23:28:54
【问题描述】:

我正在尝试使用一个函数来确保我需要的表已经创建,如果没有创建它。这是示例:

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,或者记录信息的第二个参数实际上应该是可以从源代码中检索的记录?

【问题讨论】:

    标签: erlang record mnesia


    【解决方案1】:

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

    我不认为您的功能真的太具有防御性,因为您正在做的是发出更具体的错误信号。如果你要返回 {error, ...},那就另当别论了。

    最后一点是,如果您要引发异常,则不应使用throw/1,而应使用erlang:error/1throw 用于非本地返回(用catch 捕获),而erlang:error 用于引发异常。在许多情况下,结果可能相同,但实际错误值可能具有误导性 (nocatch)。越清楚地表明你的意图总是越好,在这种情况下,这是一个错误信号。

    附:是的,我知道catch 也可以捕获错误/退出。这是故意的。在一个完美的世界中,catch 应该只捕获抛出,try 只应该捕获错误/退出。

    【讨论】:

      【解决方案2】:

      不幸的是,即使它看起来像一个函数,record_info 也不是一个真正的函数。

      您可以通过测试以下内容来验证这一点。创建文件:

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

      启动 Erlang shell:

       > 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}}

      【讨论】:

        【解决方案3】:

        您可能想看看Ulf Wiger's exprecs

        阅读描述:

        模块是一个解析变换 允许您导出记录。这 transform 为 实例化、检查和 修改记录,无需 引入编译时依赖 模块之间。

        话说,你的功能对我来说听起来有点防御性。以下页面解释了为什么在 Erlang 中进行防御性编程是一个坏习惯:

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

        【讨论】:

        • 我知道在 Erlang 中进行防御性编程的坏习惯,但我不明白这与我的功能有什么关系?我只是想确保我没有创建架构。
        猜你喜欢
        • 2018-09-18
        • 2017-06-10
        • 2016-09-18
        • 1970-01-01
        • 1970-01-01
        • 2010-12-22
        • 2015-05-24
        • 2016-10-29
        • 2016-06-21
        相关资源
        最近更新 更多