给定一个记录
-record(something, {id :: integer(),
name :: string(),
email = undefined :: string() | undefined}).
#something.email
有没有办法获得字段的默认值,在这个例子中得到默认为未定义的事实?
记录是 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
.
构造空记录并查看一些字段:(#something{})#something.email
。