给出记录
-record(something, {id :: integer(),
name :: string(),
email = undefined :: string() | undefined}).
有没有办法获取字段的默认值,在这个例子中得到#something.email
默认为undefined的事实?
答案 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
。