找到你要的答案

Q:Fields with common names in different records

Q:不同记录中具有通用名称的字段

I have some records with similar fields, like this:

-define(COMMON_FIELDS, common1, common2, common3).
-record(item1, a, b, c, ?COMMON_FIELDS).
-record(item2, x, y, z, ?COMMON_FIELDS).

But later I need to write similar code for every record:

Record#item1.common1,
Record#item1.common2,
Record#item1.common3

and:

Record#item2.common1,
Record#item2.common2,
Record#item2.common3

Is there way to write one function for access to same fields in different records?

我有一些类似领域的记录,像这样:

-define(COMMON_FIELDS, common1, common2, common3).
-record(item1, a, b, c, ?COMMON_FIELDS).
-record(item2, x, y, z, ?COMMON_FIELDS).

但后来我需要为每个记录写类似的代码:

Record#item1.common1,
Record#item1.common2,
Record#item1.common3

和:

Record#item2.common1,
Record#item2.common2,
Record#item2.common3

是否有写一个函数来访问不同记录中的同一字段?

answer1: 回答1:

Is there way to write one function for access to same fields in different records?

1) Pattern matching in multiple function clauses:

-module(x1).
-export([read/1]).
-define(COMMON_FIELDS, common1, common2, common3).

-record(item1, {x, ?COMMON_FIELDS}).  %Note that you defined your records incorrectly.
-record(item2, {y, ?COMMON_FIELDS}).

read(#item1{common1=C1, common2=C2, common3=C3} = _Item) ->
    io:format("~p, ~p, ~p~n", [C1, C2, C3]);
read(#item2{common1=C1, common2=C2, common3=C3} = _Item) ->
    io:format("~p, ~p, ~p~n", [C1, C2, C3]).

...

25> c(x1).
{ok,x1}
26> rr(x1).
[item1,item2]

27> A = #item1{x=10, common1="hello", common2="world", common3="goodbye"}.
#item1{x = 10,common1 = "hello",common2 = "world",
       common3 = "goodbye"}

28> B = #item2{y=20, common1="goodbye", common2="mars", common3="hello"}.  
#item2{y = 20,common1 = "goodbye",common2 = "mars",
       common3 = "hello"}

29> x1:read(A).                                                            
"hello", "world", "goodbye"
ok

30> x1:read(B).                                                            
"goodbye", "mars", "hello"
ok

Note the export statement--it's a list of length 1, i.e. the module exports one function. The output shows that the read() function can read records of either type.

2) A case statement:
If for some reason, by stating one function you mean one function clause, you can do this:

read(Item) ->
    case Item of
        #item1{common1=C1, common2=C2, common3=C3} -> true;
        #item2{common1=C1, common2=C2, common3=C3} -> true
    end,

    io:format("~p, ~p, ~p~n", [C1, C2, C3]).

Is there way to write one function for access to same fields in different records?

1)多功能分句的模式匹配:

-module(x1).
-export([read/1]).
-define(COMMON_FIELDS, common1, common2, common3).

-record(item1, {x, ?COMMON_FIELDS}).  %Note that you defined your records incorrectly.
-record(item2, {y, ?COMMON_FIELDS}).

read(#item1{common1=C1, common2=C2, common3=C3} = _Item) ->
    io:format("~p, ~p, ~p~n", [C1, C2, C3]);
read(#item2{common1=C1, common2=C2, common3=C3} = _Item) ->
    io:format("~p, ~p, ~p~n", [C1, C2, C3]).

25> c(x1).
{ok,x1}
26> rr(x1).
[item1,item2]

27> A = #item1{x=10, common1="hello", common2="world", common3="goodbye"}.
#item1{x = 10,common1 = "hello",common2 = "world",
       common3 = "goodbye"}

28> B = #item2{y=20, common1="goodbye", common2="mars", common3="hello"}.  
#item2{y = 20,common1 = "goodbye",common2 = "mars",
       common3 = "hello"}

29> x1:read(A).                                                            
"hello", "world", "goodbye"
ok

30> x1:read(B).                                                            
"goodbye", "mars", "hello"
ok

注意导出语句--它是长度为1的列表,即模块输出一个函数。结果表明,read()功能可以读取任何类型的记录。

2) A case statement:
If for some reason, by stating one function you mean one function clause, you can do this:

read(Item) ->
    case Item of
        #item1{common1=C1, common2=C2, common3=C3} -> true;
        #item2{common1=C1, common2=C2, common3=C3} -> true
    end,

    io:format("~p, ~p, ~p~n", [C1, C2, C3]).
answer2: 回答2:

You can use exprecs parse transform from parse_transe.

-module(parse).
-compile({parse_transform, exprecs}).

-record(item1, {x, common1, common2}).
-record(item2, {y, common1, common2}).

-export_records([item1, item2]).

-export([p/0]).

f() ->
    R1 = #item1{x=1, common1=foo1, common2=bar1},
    R2 = #item2{y=2, common1=foo2, common2=bar2},

    ['#get-'(Field, Rec) || Field <- [common1, common2], Rec <- [R1, R2]].

...

1> c(parse).
{ok,parse}
2> parse:f().
[foo1,foo2,bar1,bar2]

你可以使用exprecs解析变换从parse_transe。

-module(parse).
-compile({parse_transform, exprecs}).

-record(item1, {x, common1, common2}).
-record(item2, {y, common1, common2}).

-export_records([item1, item2]).

-export([p/0]).

f() ->
    R1 = #item1{x=1, common1=foo1, common2=bar1},
    R2 = #item2{y=2, common1=foo2, common2=bar2},

    ['#get-'(Field, Rec) || Field <- [common1, common2], Rec <- [R1, R2]].

1> c(parse).
{ok,parse}
2> parse:f().
[foo1,foo2,bar1,bar2]
answer3: 回答3:

It might make sense to factor out the common fields into a single field in each record companies containing a record with all the common data or even a tulple. Then refactor your code to do all common processing to its own function.

You still need to pattern match every top level record to get the common sub record. But somewhere you probably want to do the processing specific to each record kind and there you can already match out the common field.

-record(common, {c1, c2, c3}).
-record(item1, {a, b, c, com}).
...

process_item(#item1{a=A, b=B, c=C, com=Com}) ->
     process_abc(A, B, C),
     process_common(Com),
     ...;
process_item(#item2{x=X, y=Y ...

Data structures like this might also be a indication to use the new Map data type instead of records.

它可以分解出公共领域到一个领域中的每个记录包含一个记录公司所有常见的数据甚至tulple意义。然后重构你的代码做了所有常见的处理自己的职能。

您仍然需要模式匹配每个顶级记录,以获得公共子记录。但在某处你可能想对每个记录类型进行处理,在那里你可以匹配公共字段。

-record(common, {c1, c2, c3}).
-record(item1, {a, b, c, com}).
…

process_item(#item1{a=A, b=B, c=C, com=Com}) ->
     process_abc(A, B, C),
     process_common(Com),
     …;
process_item(#item2{x=X, y=Y …

这样的数据结构也可以指示使用新的地图数据类型而不是记录。

erlang