【问题标题】:erlang records troubleerlang记录麻烦
【发布时间】:2011-07-21 08:41:37
【问题描述】:

我正在努力处理我的一个模块中的记录。

我在代码顶部定义了一条记录:

-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}]

谁能指出我错过了什么?

谢谢

【问题讨论】:

    标签: erlang records


    【解决方案1】:

    问题在于lists:filter 返回另一个列表,而不是单个元素。因此,您基本上是在尝试将列表视为记录。如果您仔细查看

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

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

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

    如果您只希望 pid 使用 lists:map:

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

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

    【讨论】:

    • 请注意,[First, Rest] 将匹配恰好包含两个元素的列表。您可能想要:[First|Rest]。或者,如果您期望得到一个结果:[First]。
    【解决方案2】:

    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].
    

    我假设您可以有多个 pid。如果你不这样做,你可以为自己节省 foreach。

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

    Pid = UserPid,

    对我来说似乎不是很有用...

    【讨论】:

    • 我会做[U || U &lt;- Users, U#user.pid =:= P]
    • 非常感谢大家!事实上,你的例子非常适合我的目的......关于 pid,我实际上并没有使用 Pid = UserPid,它只是为了澄清我想要实现的目标
    【解决方案3】:

    正如其他人所指出的,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
    

    【讨论】:

    • +1 for #user.pid 返回字段 pid 在#user 记录中的位置。
    【解决方案4】:

    您尝试显示的变量不是记录,而是一个包含一个元素的列表。此列表中的元素是您想要的记录。考虑与lists:filter 的结果匹配的模式,例如:

    案例列表:filter(GetUser, Users) 的 []-> %% 用户未找到符合该标准的用户..... [用户] 当 is_record(User,user) -> %% 用户找到。在这里做事………… List -> %% 有很多东西符合您的条件吗? 结尾, ...

    另外,请记住if statementtrue 子句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-13
      • 1970-01-01
      • 1970-01-01
      • 2010-11-11
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多