开发者

Erlang pattern matching of a list of records on receive

开发者 https://www.devze.com 2023-04-03 06:06 出处:网络
I\'m trying to create a generic receive for a part of my app that requires to wait for several updates at different times.

I'm trying to create a generic receive for a part of my app that requires to wait for several updates at different times.

This is the prototype that it is not working.

receive_info([])->[];
receive_info([RequiredInfo|RestRequiredInfos]) ->
  receive
    RequiredInfo -> [ RequiredInfo | receie_info(RestRequiredInfos)];
  end.

And it is getting called as

[UserInfo, ContextInfo] = receive_info([#userinfo{},#contextinfo{}]),

So, what I'm trying is to send a list of record types it should match and I expect a list of records received.

Not sure if this is doable, because the records set their fields to undefined and the pattern matching does not work, for example:

Trying to receive {user_info,undefined}
Other clause: instead {user_info,12} received

EDIT:

As is_record version supplied by @Adam Lindberg was not working for me I followed a bit that same way of doing things and I ended up with:

receive_infos([]) -> [];
receive_infos([Rec|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= Rec -> 
        [ Record | receiv开发者_运维问答e_infos(Records)]
end.


If you rewrite it to:

receive_info([]) -> [];
receive_info([Rec|Records]) ->
    receive
        Msg when is_record(Msg, Rec) ->
            [Msg|receive_info(Records)];
    end.

and call it as:

receive_info([userinfo, contextinfo])

it will do what you want.


I think you're on the right track with that last answer, but you can add one more check to make sure you're getting records of the correct size:

receive_infos([]) -> [];
receive_infos([Rec|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= element(1, Rec), size(Record) =:= size(Rec) -> 
        [ Record | receive_infos(Records)]
end.

Since the size and the first element atom are about all you get with records, that's probably about as good as you're gonna do.

Or arguably more straightforwardly, accept those two as arguments:

receive_infos([]) -> [];
receive_infos([{Name, Size}|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= Name, size(Record) =:= Size -> 
        [ Record | receive_infos(Records)]
end.

And call it as

receive_infos([{foo, record_info(size, foo)} | etc. ])


Several things. You're trying to match RequiredInfo (default record data) with RequiredInfo (filled record data sent as message). You therefor only expect to get data you already have which I assume might not be what you want. You also have some spelling error on receie_info.

If I wanted to fill a list of default records with received populated records and all records must be received or everything fail, I would probably do something like this.

fill_records(List)   -> fill_records(List,length(List)).
fill_records(List,0) -> List;
fill_records(List,N) ->
    receive Rec -> fill_records(lists:keyreplace(element(1,Rec),1,List,Rec),N-1)
    after 5000 -> {error,timeout} end.

You should secure this by protecting against receiving several instances of the same record type or unwanted record types, depending on the surrounding system.

You could of course also just create a receive loop where you only define the number of messages to expect, or maybe look at gen_fsm or gen_server and their internal states and message handling.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号