简体   繁体   中英

How to define function with record argument in erlang

I want to define the structure of my function input.

This module defines my function (part of it is pseudo code):

-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.

This is how I want to call it:

-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]).

So, any idea how I can force the type of the function input to be of type my_record?

It's often handy to destructure a record directly in the function argument list, which also forces that argument to have the desired record type. For example, we can slightly modify your my_function/2 like this:

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.

Note how we're pattern-matching the second parameter MyValue : we're not only asserting that it's a #my_record{} instance, but we're also extracting its name field into the Name variable at the same time. This is handy because we use Name on the first line of the function body. Note that we also keep the parameter name MyValue because we pass it to parse_response/2 within the function body. If we didn't need it, we could instead write the function head like this:

my_function(ClientRequest, #my_record{name=Name}) ->

This would still have the desired effect of forcing the second argument to be of type #my_record{} , and would also still extract Name . If desired, you could extract other fields in a similar manner:

my_function(ClientRequest, #my_record{name=Name, id=Id}) ->

Both Name and Id are then available for use within the function body.

One other thing: don't use the atom null as a default for your record fields. The default for Erlang record fields is the atom undefined , so you should just use that. This is preferable to defining your own concept of null in the language.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM