有没有办法对默认记录值进行查找?

时间:2013-08-08 01:05:57

标签: erlang records

给出记录

-record(something, {id                :: integer(),
                    name              :: string(),
                    email = undefined :: string() | undefined}).

有没有办法获取字段的默认值,在这个例子中得到#something.email默认为undefined的事实?

2 个答案:

答案 0 :(得分:7)

记录是Erlang中的语法糖,由编译器扩展。 @Dmitry建议的以下解决方案有效,但编译器不会优化它,除非你传递+内联,因为这里的技巧是真正创建一个记录:

g() -> (#something{})#something.email.

这种记录句法糖将扩展为:(使用erlc -E

g() ->
    case {something,undefined,undefined,undefined} of
        {something,_,_,rec0} ->
            rec0;
        _ ->
            error({badrecord,something})
    end.

这将最终成为:(使用erlc -S

{function, g, 0, 4}.
  {label,3}.
    {line,[{location,"test.erl",10}]}.
    {func_info,{atom,test},{atom,g},0}.
  {label,4}.
    {move,{literal,{something,undefined,undefined,undefined}},{x,0}}.
    {test,is_tuple,{f,5},[{x,0}]}.
    {test,test_arity,{f,5},[{x,0},4]}.
    {get_tuple_element,{x,0},0,{x,1}}.
    {get_tuple_element,{x,0},3,{x,2}}.
    {test,is_eq_exact,{f,5},[{x,1},{atom,something}]}.
    {move,{x,2},{x,0}}.
    return.
  {label,5}.
    if_end.

表达式的#something.email部分不仅意味着获取已创建记录的电子邮件字段,还要检查传递的记录是否格式正确。默认情况下,此测试目前尚未优化。幸运的是,您可以使用模块中的-compile([inline]).或命令行中的+inline对其进行优化。

以下解决方案对于编译器来说更简单:

f() -> element(#something.email, #something{}).

记录语法糖(这里#sysies.email是电子邮件字段的索引)将扩展为:

f() ->
    element(4, {something,undefined,undefined,undefined}).

在这种情况下,我们不会告诉Erlang测试#something{}是否是正确的#something记录。编译器始终优化对element/2内置函数的调用。所以最终会变成:

{function, f, 0, 2}.
  {label,1}.
    {line,[{location,"test.erl",7}]}.
    {func_info,{atom,test},{atom,f},0}.
  {label,2}.
    {move,{atom,undefined},{x,0}}.
    return.

请注意,除非明确提供,否则任何字段的默认值均为undefined。结果,您的代码:

-record(something, {id                :: integer(),
                    name              :: string(),
                    email = undefined :: string() | undefined}).

相当于:

-record(something, {id    = undefined :: integer() | undefined,
                    name  = undefined :: string()  | undefined,
                    email = undefined :: string()  | undefined}).

然而,您的代码似乎意味着ID始终为integer()且永远不会undefined,同样该名称始终为string()。这是不真实的。如果这是您的意思,则应提供与undefined不同的默认值:

-record(something, {id    = 0   :: integer(),
                    name  = ""  :: string(),
                    email       :: string()}).

仅提供默认值会告诉dialyzer ID和名称永远不会是undefined

答案 1 :(得分:4)

构造空记录并查看某些字段:(#something{})#something.email