2011-07-21 73 views
6

我正在與我的模塊之一的記錄掙扎。erlang記錄麻煩

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

任何人都可以指出我錯過了什麼?

感謝

回答

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

我假設你可以有多個的PID。如果你不這樣做,你可以爲自己省下一筆錢。

我相信在這種情況下使用list comprehensions會使代碼更具可讀性。此外,以下內容:

PID = UserPid,

不看我很大的忙......

+0

+1非常整齊的Erlang例子。 –

+3

我會做'[U || U < - 用戶,U#user.pid =:= P]'。 –

+0

@Adam Lindberg:+1。更可讀。 –

11

的問題是,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。

+2

注意[第一靜止]將對陣正好用兩個元素的列表。你可能想要:[First | Rest]。或者,如果您期待得到一個結果:[首先]。 –

+1

@Roberto - 對,謝謝。 –

0

您嘗試顯示的變量不是記錄,而是其中包含一個元素的列表。該列表中的元素是您想要的記錄。考慮模式匹配的情況下lists:filter語句的結果是這樣的:

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

另外,記得if statementtrue條款。

4

正如其他人所指出的那樣,lists:filter/2返回一個列表,即使它是隻是一個單一的元素。你要找的功能是lists:keyfind/3(二郎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

+1#user.pid返回字段的位置在#用戶記錄中的pid。 – justin