Erlang шаблон сопоставления списка записей при получении - PullRequest
0 голосов
/ 05 сентября 2011

Я пытаюсь создать общий прием для части моего приложения, которая требует ожидания нескольких обновлений в разное время.
Это прототип, который не работает.

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

И это называется

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

Итак, я пытаюсь отправить список типов записей, которым он должен соответствовать, и я ожидаю список полученных записей.
Не уверен, что это выполнимо, потому что записи устанавливают свои поля как неопределенные и сопоставление с образцом не работает, например:

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

EDIT:
Поскольку версия is_record, предоставленная @Adam Lindberg, не работала для меня, я немного придерживался того же способа, и в итоге я получил:

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 | receive_infos(Records)]
end.

Ответы [ 3 ]

3 голосов
/ 05 сентября 2011

Если переписать его на:

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

и назвать его как:

receive_info([userinfo, contextinfo])

, он будет делать то, что вы хотите.

2 голосов
/ 06 сентября 2011

Я думаю, что вы на правильном пути с этим последним ответом, но вы можете добавить еще одну проверку, чтобы убедиться, что вы получаете записи правильного размера:

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.

Поскольку размер и первый атом элемента - это почти все, что вы получаете с записями, это, вероятно, примерно так же хорошо, как и вы.

Или, возможно, более просто, примите эти два в качестве аргумента:

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.

И назовите это

receive_infos([{foo, record_info(size, foo)} | etc. ])
1 голос
/ 05 сентября 2011

Несколько вещей. Вы пытаетесь сопоставить RequiredInfo (данные записи по умолчанию) с RequiredInfo (данные заполненной записи, отправленные в виде сообщения). Поэтому вы ожидаете получить только те данные, которые у вас уже есть, которые, как я полагаю, могут не соответствовать вашим ожиданиям. У вас также есть некоторая орфографическая ошибка на receie_info.

Если бы я хотел заполнить список записей по умолчанию полученными заполненными записями и все записи должны быть получены, или все не удалось, я, вероятно, сделал бы что-то подобное.

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.

Вы должны обеспечить это, защищая от получения нескольких экземпляров одного и того же типа записи или нежелательных типов записи, в зависимости от окружающей системы.

Конечно, вы также можете просто создать цикл приема, в котором вы только определяете количество ожидаемых сообщений, или, возможно, посмотрите на gen_fsm или gen_server и их внутренние состояния и обработку сообщений.

...