是否可以使用记录名作为参数?

nag*_*aru 7 erlang

让我们说我有一个记录:

-record(foo, {bar}).
Run Code Online (Sandbox Code Playgroud)

我想要做的是能够将记录名称作为参数传递给函数,并获取新记录.该函数应该是通用的,以便它应该能够接受任何记录,如下所示.

make_record(foo, [bar], ["xyz"])
Run Code Online (Sandbox Code Playgroud)

实现这样的功能时我试过这个:

make_record(RecordName, Fields, Values) ->
    NewRecord = #RecordName{} %% this line gives me an error: syntax error before RecordName
Run Code Online (Sandbox Code Playgroud)

是否可以将记录名称用作参数?

Lii*_*Lii 8

如果在编译期间无权访问记录,则无法使用记录语法.

但是因为在编译期间简单地将记录转换为元组,所以我们很容易手动构建它们:

-record(some_rec, {a, b}).

make_record(Rec, Values) ->
    list_to_tuple([Rec | Values]).

test() ->
    R = make_record(some_rec, ["Hej", 5]),  % Dynamically create record
    #some_rec{a = A, b = B} = R,            % Access it using record syntax
    io:format("a = ~p, b = ~p~n", [A, B]).  
Run Code Online (Sandbox Code Playgroud)

或者,如果您在编译时列出了该函数应该能够构造的所有记录,您还可以使用字段名称:

%% List of record info created with record_info macro during compile time
-define(recs, 
    [
     {some_rec, record_info(fields, some_rec)}
    ]).

make_record_2(Rec, Fields, Values) ->
    ValueDict = lists:zip(Fields, Values),

    % Look up the record name and fields in record list
    Body = lists:map(
         fun(Field) -> proplists:get_value(Field, ValueDict, undefined) end,
         proplists:get_value(Rec, ?recs)),

    list_to_tuple([Rec | Body]).

test_2() ->
    R = make_record_2(some_rec, [b, a], ["B value", "A value"]),
    #some_rec{a = A, b = B} = R,
    io:format("a = ~p, b = ~p~n", [A, B]).
Run Code Online (Sandbox Code Playgroud)

使用第二个版本,您还可以进行一些验证,以确保使用正确的字段等.

在动态处理记录时要记住的其他有用构造是#some_rec.a表达式,它计算s中a字段的索引,给定元组和索引some_recelement(N, Tuple)函数返回该索引中的元素.


Zed*_*Zed 5

这是不可能的,因为记录是仅编译时的结构。在编译时,它们将转换为元组。因此,编译器需要知道记录的名称,因此您不能使用变量。

您还可以使用一些解析转换魔术(请参阅exprecs)来创建记录构造函数和访问器,但是这种设计似乎朝错误的方向进行。如果需要动态创建类似记录的内容,则可以改用某些结构,例如键值列表dict

  • 它们被转换为元组,而不是数组。 (2认同)