记录是 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.
The #something.email
表达式的一部分不仅意味着获取创建的记录的电子邮件字段,还意味着检查传递的记录是否格式良好。该测试目前默认未优化。幸运的是,您可以使用以下方法对其进行优化-compile([inline]).
在你的模块中或+inline
在命令行上。
对于编译器来说,以下解决方案更简单:
f() -> element(#something.email, #something{}).
记录语法糖(这里#something.email是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.
请注意,任何字段的默认值is 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 http://www.erlang.org/doc/man/dialyzer.htmlid 和 name 永远不可能undefined
.