문제

통화 대기열에 있는 에이전트의 현재 상태를 수집하는 소프트웨어에 대한 일부 코드를 리팩터링하려고 합니다.현재 내가 수신하는 6개 정도의 이벤트 각각에 대해 Mnesia 테이블에서 에이전트가 있는지 확인하고 이벤트에 따라 행의 일부 값을 변경하거나 에이전트가 없으면 새로 추가합니다.현재 저는 각 이벤트마다 이 Mnesia 트랜잭션을 가지고 있으며 물론 이는 에이전트의 존재 등을 확인하기 위한 반복적인 코드입니다.

다음과 같은 기능이 하나 있도록 변경하려고합니다. 변경 에이전트/2 나를 위해 이것을 처리하는 이벤트에서 호출합니다.

내 문제는 물론 기록이다....나는 그것들을 동적으로 생성하거나 그 중 2개를 병합하는 등의 방법을 찾지 못했습니다.바람직하게는 다음과 같이 호출할 수 있는 함수가 있습니다.

change_agent("001", #agent(id = "001", name = "Steve")).
change_agent("001", #agent(id = "001", paused = 0, talking_to = "None")).
도움이 되었습니까?

해결책

나는 얼마 전에 두 개의 레코드를 병합하는 코드를 작성했습니다.완전히 동적이지는 않지만 매크로를 사용하면 여러 레코드에 쉽게 사용할 수 있습니다.

다음과 같이 작동합니다.merge/2 함수는 두 개의 레코드를 가져와 참조용 빈 레코드와 함께 목록으로 변환합니다(레코드 유형은 컴파일 타임에 정의되며 그래야 합니다.이것이 "비동적" 부분입니다).그런 다음 목록과 함께 작동하고 정의된 경우 A에서 요소를 가져오고, 정의된 경우 B에서 요소를 가져오고, 마지막으로 항상 정의된 기본값에서 요소를 가져오는 일반 함수 merge/4를 통해 실행됩니다.

코드는 다음과 같습니다(StackOverflow의 잘못된 Erlang 구문 강조를 양해해 주세요).

%%%----------------------------------------------------------------------------
%%% @spec merge(RecordA, RecordB) -> #my_record{}
%%%     RecordA = #my_record{}
%%%     RecordB = #my_record{}
%%%
%%% @doc Merges two #my_record{} instances. The first takes precedence.
%%% @end
%%%----------------------------------------------------------------------------
merge(RecordA, RecordB) when is_record(RecordA, my_record),
                             is_record(RecordB, my_record) ->
    list_to_tuple(
        lists:append([my_record],
                     merge(tl(tuple_to_list(RecordA)),
                           tl(tuple_to_list(RecordB)),
                           tl(tuple_to_list(#my_record{})),
                           []))).

%%%----------------------------------------------------------------------------
%%% @spec merge(A, B, Default, []) -> [term()]
%%%     A = [term()]
%%%     B = [term()]
%%%     Default = [term()]
%%%
%%% @doc Merges the lists `A' and `B' into to a new list taking
%%% default values from `Default'.
%%%
%%% Each element of `A' and `B' are compared against the elements in
%%% `Default'. If they match the default, the default is used. If one
%%% of them differs from the other and the default value, that element is
%%% chosen. If both differs, the element from `A' is chosen.
%%% @end
%%%----------------------------------------------------------------------------
merge([D|ATail], [D|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [D|To]); % If default, take from D
merge([D|ATail], [B|BTail], [D|DTail], To) ->
    merge(ATail, BTail, DTail, [B|To]); % If only A default, take from B
merge([A|ATail], [_|BTail], [_|DTail], To) ->
    merge(ATail, BTail, DTail, [A|To]); % Otherwise take from A
merge([],        [],        [],        To) ->
    lists:reverse(To).

원하는 방식으로 자유롭게 사용해 보세요.

다른 팁

레코드에 대한 일반 액세스 함수를 작성하는 것은 어렵습니다.이에 대한 한 가지 해결 방법은 다음과 같습니다. '표현' 저수준 레코드 액세스 기능에 대한 코드를 생성하는 라이브러리.

당신이해야 할 일은 다음 줄을 모듈에 추가하는 것입니다.

-compile({parse_transform, exprecs}).
-export_records([...]).  % name the records that you want to 'export'

액세스 기능에 대한 명명 규칙은 이상해 보일 수 있지만 Richard O'Keefe의 제안에서 영감을 받았습니다.최소한 일관성이 있으며 기존 기능과 충돌할 가능성이 없습니다.(:

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top