erlang记录麻烦

时间:2011-07-21 08:41:37

标签: erlang records

我正在努力学习其中一个模块中的记录。

我在我的代码之上定义了一条记录:

-record(user,  {pid,
                name,
                nick}).

用少数几个词表示每个用户将被表示为具有自己的pid和其他字段的进程。

稍后在模块中,我正在执行以下操作:

Pid = UserPid,
GetUser = fun(X) ->
                if X#user.pid =:= Pid -> true; 
                   X#user.pid=/= Pid -> false 
                end 
      end,
User = lists:filter(GetUser, Users),
io:format("User pid is ~p~n",[User#user.pid]).

运行此代码我得到:

** exception error: {badrecord,user}

但如果我这样做:

io:format("User ~p~n",[User]).       

打印

User [{user,<0.33.0>,name1,nick1}]

有人能说出我错过的东西吗?

由于

4 个答案:

答案 0 :(得分:11)

问题是lists:filter返回另一个列表,而不是单个元素。所以你基本上试图将列表视为记录。如果仔细查看

的输出
io:format("User ~p~n",[User])
%% User [{user,<0.33.0>,name1,nick1}]

您会注意到该语句包含在[]中。这是一个清单。如果您只需要第一个用户

[First | Rest] = lists:filter(GetUser, Users)

如果您只想使用lists:map

UsersWithPid = lists:filter(GetUser, Users),
Pids = lists:map(fun(U) -> U#user.pid end, UsersWithPid).

现在Pids是包含带有pid的用户的pids的列表。

答案 1 :(得分:7)

Emil关于the lists:filter函数的答案是正确的。

这就是我重写代码的方式:

-module(com).

-record(user,  {pid,
                name,
                nick}).

-export([lookup/1]).

lookup(Pid) ->
    Users = users(),
    FilteredUsers = [User || #user{pid = P} = User <- Users, Pid =:= P],
    lists:foreach(fun display/1, FilteredUsers).

display(User) ->
    io:format("User name  is ~p~n",[User#user.name]).   

users() ->
    User1 = #user{pid = 1, name = "Bob", nick = "bob"},
    User2 = #user{pid = 2, name = "Alice", nick = "alice"},
    User3 = #user{pid = 1, name = "Charlie", nick = "charlie"},
    [User1, User2, User3].

我假设你可以有多个pids。如果你不这样做,你可以节省你自己的预备。

我相信在这种情况下使用list comprehensions会使代码更具可读性。另外,以下内容:

  

Pid = UserPid,

对我来说看起来不太有用......

答案 2 :(得分:4)

正如其他人所指出的那样,lists:filter/2会返回一个列表,即使它只是一个元素。您正在寻找的函数是lists:keyfind/3(在Erlang R14B03中,对于R13B04及更早版本,使用lists:keysearch/3):

Eshell V5.8.4  (abort with ^G)
1> rd(user, {pid, name, nick}).
user

2> Users = [#user{pid = spawn(fun() -> ok end), name = name1, nick = nick1},
2>          #user{pid = spawn(fun() -> ok end), name = name2, nick = nick2},
2>          #user{pid = spawn(fun() -> ok end), name = name3, nick = nick3}].
[#user{pid = <0.34.0>,name = name1,nick = nick1},
 #user{pid = <0.35.0>,name = name2,nick = nick2},
 #user{pid = <0.36.0>,name = name3,nick = nick3}]

3> lists:keysearch(pid(0,35,0), #user.pid, Users).
{value,#user{pid = <0.35.0>,name = name2,nick = nick2}}

4> lists:keyfind(pid(0,35,0), #user.pid, Users).
#user{pid = <0.35.0>,name = name2,nick = nick2}

5> lists:keyfind(pid(0,99,0), #user.pid, Users).
false

lists:keyfind/3是首选,因为它更简单。

仅使用#user.pid会在pid记录中返回字段#user的位置:

6> #user.pid.
2

答案 3 :(得分:0)

您要显示的变量不是记录,而是包含其中一个元素的List。此列表中的元素是您想要的记录。考虑模式匹配lists:filter in case语句的结果,如下所示:

case lists:filter(GetUser, Users) of
   [] -> 
       %% user not found against that criteria.....
   [User] when is_record(User,user) -> 
     %% user found. Do things here........
   List -> %% are many things matching your criteria ?
end,
...

另外,请记住true的{​​{1}}子句。