我想定义函数输入的结构。
这个模块定义了我的函数(部分是伪代码):
-module(my_service).
-export([my_function/2]).
-type my_enum() :: 1 | 2 | 5.
-record(my_record, {id = null :: string(), name = null :: string(), myType = null :: my_enum()}).
-spec my_function(MyValue#my_record) -> Result#my_record.
my_function(ClientRequest, MyValue) when is_record(Entry, my_record) ->
Response = client:request(get, "http://www.example.com/api?value=" + MyValue#my_record.name),
case Response of
{ok, Status, Head, Body} ->
Result = parse_response(Body, my_record);
Error ->
Error
end.
这就是我想要的方式:
-module(test1).
-import(io, [format/2]).
main(_) ->
application:start(inets),
MyTestValue = #my_record{name => "test value", myType => 2},
X = my_service:my_function(MyTestValue),
io:format("Response: ~p", [X]).
那么,任何想法如何强制函数输入的类型为my_record类型?
答案 0 :(得分:6)
直接在函数参数列表中构造记录通常很方便,这也会强制该参数具有所需的记录类型。例如,我们可以稍微修改您的my_function/2
:
my_function(ClientRequest, #my_record{name=Name}=MyValue) ->
Response = client:request(get, "http://www.example.com/api?value=" ++ Name),
case Response of
{ok, Status, Head, Body} ->
Result = parse_response(Body, MyValue);
Error ->
Error
end.
请注意我们如何对第二个参数MyValue
进行模式匹配:我们不仅断言它是#my_record{}
个实例,而且我们还将其name
字段提取到Name
变量同时出现。这很方便,因为我们在函数体的第一行使用Name
。请注意,我们还保留参数名称MyValue
,因为我们将其传递给函数体内的parse_response/2
。如果我们不需要它,我们可以改为编写函数头:
my_function(ClientRequest, #my_record{name=Name}) ->
这仍然会产生强制第二个参数为#my_record{}
类型的预期效果,并且仍会提取Name
。如果需要,您可以以类似的方式提取其他字段:
my_function(ClientRequest, #my_record{name=Name, id=Id}) ->
然后Name
和Id
都可以在函数体中使用。
另一件事:不要将原子null
用作记录字段的默认值。 Erlang记录字段的默认值是原子undefined
,因此您应该使用它。这比在语言中定义自己的null
概念更可取。