Эрланг записывает проблемы - PullRequest
6 голосов
/ 21 июля 2011

Я борюсь с записями в одном из моих модулей.

Я определил поверх моего кода запись как:

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

11 голосов
/ 21 июля 2011

Проблема в том, что 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 - это список сpids пользователей с pid.

7 голосов
/ 21 июля 2011

Ответ Эмиля о функции 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].

Полагаю, у вас может быть несколько пидов. Если вы этого не сделаете, вы можете сохранить себе foreach.

Я считаю, что использование списочных пониманий в этом случае делает код намного более читабельным. Также следующее:

Pid = UserPid,

не выглядит для меня очень полезным ...

4 голосов
/ 21 июля 2011

Как уже отмечали другие, 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
0 голосов
/ 21 июля 2011

переменная, которую вы пытаетесь отобразить, является не записью, а списком с одним элементом внутри. Элементом в этом списке является запись, которую вы хотите. Рассмотрим шаблон, совпадающий с результатом вашего lists:filter в выражении 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 в if statement.

...