繁体   English   中英

编译错误:在Erlang中记录宏的替换

[英]compilation error: record replacement of macro in Erlang

这是目录结构。

SRC /
animal.hrl
people.hrl
data_animal.erl
data_people.erl
test.erl
test_macro.erl

animal.hrl

%% The record definition of animal.

-ifndef(ANIMAL).
-define(ANIMAL,true).

-record(animal,{
  id,
  animal_name,
  age
}).

-endif.

people.hrl

%% The record definition of people.

-ifndef(PEOPLE).
-define(PEOPLE,true).

-record(people,{
  id,
  people_name,
  age
}).

-endif.

data_animal.erl

%% The data file of animal.

-module(data_animal).
-include("animal.hrl").

%% API
-export([get/1,get_ids/0]).

get(1)->
  #animal{
    id=1,
    animal_name="cat",
    age=23
  };
get(2)->
  #animal{
    id=2,
    animal_name="dog",
    age=19
  };
get(3)->
  #animal{
    id=3,
    animal_name="tiger",
    age=23
  };
get(4)->
  #animal{
    id=4,
    animal_name="pig",
    age=19
  };
get(_)->
  undefined.

get_ids()->
  [1,2,3,4].

data_people.erl

%% The data file of people.

-module(data_people).
-include("people.hrl").

%% API
-export([get/1,get_ids/0]).

get(1)->
  #people{
    id=1,
    people_name="John",
    age=23
  };
get(2)->
  #people{
    id=2,
    people_name="Ken",
    age=19
  };
get(3)->
  #people{
    id=3,
    people_name="Tom",
    age=23
  };
get(4)->
  #people{
    id=4,
    people_name="Healthy",
    age=19
  };
get(_)->
  undefined.

get_ids()->
  [1,2,3,4].

请注意,对于data_animal.erldata_people.erlget/1的参数是返回值的记录ID,而get_ids/0的返回值是get/1的参数列表。

test.erl

-module(test).

%% API
-export([get_animal_list/1,get_people_list/1]).

-include("animal.hrl").
-include("people.hrl").

get_animal_list(Age)->
  Fun=fun(Id,Acc)->
    case data_animal:get(Id) of
      #animal{age=Age}=Conf->
        [Conf|Acc];
      _->
        Acc
    end
      end,
  lists:foldl(Fun,[],data_animal:get_ids()).

get_people_list(Age)->
  Fun=fun(Id,Acc)->
    case data_people:get(Id) of
      #people{age=Age}=Conf->
        [Conf|Acc];
      _->
        Acc
    end
      end,
  lists:foldl(Fun,[],data_people:get_ids()).

我想获取年龄为23岁的动物和人的数据,因此我编写了2个函数get_animal_list/1, get_people_list/1

我跑

1> c(data_animal),c(data_people),c(test).
{ok,test}
2> test:get_people_list(23).
[{people,3,"Tom",23},{people,1,"John",23}]
3> test:get_animal_list(23).
[{animal,3,"tiger",23},{animal,1,"cat",23}]

突然,我发现这两个函数共享相同的模式。 然后,我尝试编写宏get_list ,并进行2次调用。

test_macro.erl

-module(test_macro).

%% API
-export([get_animal_list/1,get_people_list/1]).

-include("animal.hrl").
-include("people.hrl").

-define(get_list(DataMod,Record,Age),(
  Fun=fun(Id,Acc)->
    case DataMod:get(Id) of
      #Record{age=Age}=Conf->
        [Conf|Acc];
      _->
        Acc
    end
  end,
  lists:foldl(Fun,[],DataMod:get_ids())
)).

get_animal_list(Age)->
  ?get_list(data_animal,animal,Age).

get_people_list(Age)->
  ?get_list(data_people,people,Age).

但是我得到了编译错误:

4> c(test_macro).
test_macro.erl:22: syntax error before: ','
test_macro.erl:25: syntax error before: ','
test_macro.erl:4: function get_animal_list/1 undefined
test_macro.erl:4: function get_people_list/1 undefined
error

告诉我为什么〜y〜y〜

谢谢你们! 我现在有3个问题。

  1. 我的代码真的不像Erlang吗? 它是从我公司的项目中提取的。 我还在想OOP吗? 还是我公司的编程人员呢?
  2. 感谢@mlambrichs的建议。 它可以工作,但是我仍然想知道为什么我的代码会出现编译错误? 是否因为Erlang预处理程序是#Record{age=Age}扫描程序,所以无法识别#Record{age=Age}
  3. 根据@mlambrichs的建议,我尝试更改宏

    -define(get_list(DataMod,Record,Age),[P || P <-list:map(fun(Id)-> DataMod:get(Id)end,DataMod:get_ids()),P#Record.age = := Age])。

转化为功能

get_list(DataMod, Record, Age)->
  [P || P <- lists:map(fun(Id) -> DataMod:get(Id) end,
    DataMod:get_ids()),
    P#Record.age =:= Age].

然后我得到编译错误: syntax error before: Record

错误的原因是放错了'(',应将其删除:

-define(get_list(DataMod,Record,Age), (
                                     ^^^
   Fun=fun(Id,Acc)->              
     case DataMod:get(Id) of
        #Record{age=Age}=Conf->
           [Conf|Acc];
        _->
           Acc
     end
   end,
   lists:foldl(Fun,[],DataMod:get_ids())
).

编辑您添加了一些我想立即开始回答的问题。

  • 我的代码真的不像Erlang吗?
    • 宏的用法。 在您的情况下,实际上并不需要使用宏。
    • 一般而言:您想掩盖一个事实,即人类和动物使用了哪种记录。 那是实现,应该被您的界面屏蔽。 您只需要在正确的模块中定义一个可以处理此问题的getter函数即可。 PLS。 阅读我的改写建议。
  • 它可以工作,但是我仍然想知道为什么我的代码会出现编译错误? 请参阅答案顶部。
  • ....我尝试更改宏....是的,该函数无法编译。 显然需要重写。

像这样:

get_list(DataMod, Age) ->
    [ P || P = {_,_,_,A} <- lists:map(fun(Id) -> DataMod:get(Id) end,
           DataMod:get_ids()),
           A =:= Age].

编辑

进行重写。 您想要的是功能测试中两个列表的串联(您的test / 0,我的test / 1)。 使用逗号不会为您做到这一点。 ;-)

test(X)->
  ?get_list(data_animal,X) ++
  ?get_list(data_people,X).

让我们也修复该get_list宏。 您的宏定义get_list有3个参数,只需要2个参数。为什么已经在get_people_list / 1和get_animal_list / 1中使用Record作为参数,为什么要使用Record作为参数? 例如,尝试以下操作:

-define(get_list(DataMod, Y),
   case DataMod of
      data_animal -> get_animal_list(Y);
      data_people -> get_people_list(Y);
      _Else -> []
   end
)

总体而言,您的测试模块中有很多代码复制。 作为@yjcdll的建议的后续措施,请将接口功能(动物和人)移至其自己的模块。

让我们来看看您的数据模块及其获取功能。

我建议将所有人员记录放在一个数组中,在您的情况下,放在data_people模块中。

people() -> [
   #people{ id=1, people_name="John", age=23 },
   #people{ id=2, people_name="Ken", age=19 },
   #people{ id=3, people_name="Tom", age=23 },
   #people{ id=4, people_name="Healthy", age=19 } ].

接下来,您将需要一个getter函数来仅获取具有特定年龄的人:

get(Age) ->
   [X || X <- people(), is_age( X, Age )].

is_age / 2函数将是:

is_age( Person, Age ) ->
   Person#people.age =:= Age.

因此,在模块测试中,您的get_people_list / 1将变得更加简单。

get_people_list(Age) ->
   data_people:get(Age).

等等。 始终在寻找与您在某处已经使用过的代码看起来几乎一样的代码。 只是尝试表现一个理智,懒惰的程序员。 懒惰=好。 ;-)

编辑:OP必须坚持给定的模块。 因此,宏的重写为:

-define(get_list(DataMod, Record, Age),
   [P || P <- lists:map(fun(Id) -> DataMod:get(Id) end, 
                                   DataMod:get_ids()), 
         P#Record.age =:= Age]
).

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM