如何在erlang中使用record参数定义函数

时间:2015-09-07 16:39:44

标签: module erlang record

我想定义函数输入的结构。

这个模块定义了我的函数(部分是伪代码):

-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类型?

1 个答案:

答案 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}) ->

然后NameId都可以在函数体中使用。

另一件事:不要将原子null用作记录字段的默认值。 Erlang记录字段的默认值是原子undefined,因此您应该使用它。这比在语言中定义自己的null概念更可取。