2

给定一个记录

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

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

4

2 回答 2

7

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

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{}).

记录语法糖(这里#something.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 始终是 aninteger()和 never undefined,同样,该 name 始终是 a string()。这是不真实的。如果这是您的意思,您应该提供一个不同于以下的默认值undefined

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

仅提供默认值会告诉透析器id 和 name 永远不会是undefined.

于 2013-08-08T07:38:27.333 回答
4

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

于 2013-08-08T01:40:12.627 回答