4

にいくつかのデータを保存していますがmnesia、関連するほとんどの値を変更できるようにしたいと思います。

ナイーブ

change(RecordId, Slot, NewValue) ->
    [Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
    NewRec = Rec#rec{Slot=NewValue},
    F = fun() -> mnesia:write(NewRec) end,
    {atomic, Val} = mnesia:transaction(F),
    Val.

それをしません。コンパイラは、またはでSlotはないと文句を言います。上記のように一般的なスロット編集機能を表現する方法はありますか、それともたくさんのsを定義するのに行き詰まりますか?atom_change_slot

insertわずかに良いアプローチは、とfind部分を引き出すことです

atomic_insert(Rec) ->
    F = fun() -> mnesia:write(Rec) end,
    {atomic, Val} = mnesia:transaction(F),
    Val.

find(RecordId) -> 
    [Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
    Rec.

change(RecordId, name, NewValue) ->
    Rec = find(RecordId),
    NewRec = Rec#rec{name=NewValue},
    atomic_insert(NewRec);
change(RecordId, some_other_property, NewValue) ->
    Rec = find(RecordId),
    NewRec = Rec#rec{some_other_property=NewValue},
    ...

しかし、そこにはまだ少しコードの重複があります。そのパターンを抽象化する方法はありますか?レコードを編集できるようにするための確立された手法はありますか?一般的なアイデアはありますか?

4

3 に答える 3

4

レコードはタプルで表されるため、タプル操作を使用して個々の値を設定してみることができます。

-module(rec).
-export([field_num/1, make_rec/0, set_field/3]).
-record(rec, {slot1, slot2, slot3}).

make_rec() ->
  #rec{slot1=1, slot2=2, slot3=3}.

field_num(Field) ->
  Fields = record_info(fields, rec),
  DifField = fun (FieldName) -> Field /= FieldName end,
  case length(lists:takewhile(DifField, Fields)) of
    Length when Length =:= length(Fields) ->
      {error, not_found};
    Length ->
      Length + 2
  end.

set_field(Field, Value, Record) ->
  setelement(field_num(Field), Record, Value).

set_fieldは、更新されたレコードを返します。

Eshell V5.9.1  (abort with ^G)
1> c(rec).
{ok,rec}
2> A = rec:make_rec().
{rec,1,2,3}
3> B = rec:set_field(slot3, other_value, A).
{rec,1,2,other_value}
于 2012-05-30T21:04:24.077 に答える
3

マクロとして定義することもできますchange(特に、モジュール内でのみ使用される場合)。

-define(change(RecordId, Slot, NewValue),
        begin
            [Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
            NewRec = Rec#rec{Slot=NewValue},
            F = fun() -> mnesia:write(NewRec) end,
            {atomic, Val} = mnesia:transaction(F),
            Val
        end).

使用法:

test(R, Id) ->
    ?change(Id, name, 5).

マクロを使用する_と、フィールドとして渡すこともできます(パターンマッチングに適しています)。

于 2012-05-31T05:03:32.377 に答える
2

レコードが実際にはタプルであるという別の使用方法は、次のようになります。

change(RecordId, Index, NewValue) ->
    [Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
    NewRec = setelement(Index, Rec, NewValue),
    F = fun() -> mnesia:write(NewRec) end,
    {atomic, Val} = mnesia:transaction(F),
    Val.

あなたはこのように使うことができます:

5> Val = record:change(id58, #rec.name, new_value).

#rec.nameこれは、タプル内のフィールドのインデックスを見つけるために構文を使用しているので、タプルとしてのレコードの「クリーンな」使用でもあります。これが、この構文が追加された理由です。

于 2012-05-31T11:50:09.733 に答える