根据erlang中列表的值从记录中查找元组

根据erlang中列表的值从记录中查找元组,erlang,Erlang,我正在使用Erlang开发聊天应用程序,我想在创建客户端时存储名称,现在我只是存储Pid。我正在使用记录来存储值。 我想在客户端发送消息时获取名称,所以我必须从Pid中查找名称。我使用的是Erlang17 聊天室 -module(chat_room). -behaviour(gen_server). -export([start_link/0, enter/2, leave/1, send_message/2, find_user/1]). %% gen_server callbacks -

我正在使用Erlang开发聊天应用程序,我想在创建客户端时存储名称,现在我只是存储Pid。我正在使用记录来存储值。 我想在客户端发送消息时获取名称,所以我必须从Pid中查找名称。我使用的是Erlang17

聊天室

-module(chat_room).
-behaviour(gen_server).

-export([start_link/0, enter/2, leave/1, send_message/2, find_user/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
         code_change/3]).

-define(SERVER, ?MODULE).

-record(state, {clients=[],name}).

%%%=============================================================================
%%% API
%%%=============================================================================

start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

enter(Pid, Name) ->
    gen_server:cast(?SERVER, {enter, Pid, Name}).

leave(Pid) ->
    gen_server:cast(?SERVER, {leave, Pid}).

send_message(Pid, Message) ->
    gen_server:cast(?SERVER, {send_message, Pid, Message}).


find_user(Pid) ->
        gen_server:cast(?SERVER, {find_user, Pid}).

%%%=============================================================================
%%% gen_server callbacks
%%%=============================================================================

init([]) ->

    Dispatch = cowboy_router:compile([
        {'_', [

               {"/ws", chat_ws_handler, []},

               {"/", cowboy_static,
                [{directory, {priv_dir, chat, [<<"static">>]}},
                 {file, <<"index.html">>},
                 {mimetypes, {fun mimetypes:path_to_mimes/2, default}}]},

               {"/static/[...]", cowboy_static,
                [{directory, {priv_dir, chat, [<<"static">>]}},
                 {mimetypes, {fun mimetypes:path_to_mimes/2, default}}]}

              ]}
    ]),

    cowboy:start_http(chat, 100,
                      [{port, 8080}],
                      [{env, [{dispatch, Dispatch}]}]),
    {ok, #state{}}.

handle_call(_Request, _From, State) ->
    {noreply, State}.
handle_cast({enter, Pid, Name}, State = #state{clients= Clients}) ->
    {noreply, State#state{clients = [Pid|Clients],name=Name}};
handle_cast({leave, Pid}, State = #state{clients = Clients}) ->
    {noreply, State#state{clients  = Clients -- [Pid]}};

handle_cast({find_user, Pid}, State= #state{clients = Clients}) ->
        io:format("List: ~p", [State]),
        {noreply, State};

handle_cast({send_message, Pid, Message}, State) ->
    do_send_message(Pid, Message, State),
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    cowboy:stop_listener(chat).

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%%=============================================================================
%%% Internal functions
%%%=============================================================================

do_send_message(Pid, Message, #state{clients = Clients}) ->
    OtherPids = Clients -- [Pid],
    lists:foreach(
      fun(OtherPid) ->
              OtherPid ! {send_message, self(), Message}
      end, OtherPids).

如果我使用现有结构,如何从Pid中找到名称?

使用现有结构,我猜您会向客户机Pid发送一条消息,询问其名称,并在那里编写一个处理程序进行回复


但是,让服务器存储一个名称到pid的映射,并按名称而不是pid发送消息似乎是明智的。

我最近自己和后端实现了一个类似的应用程序,我的进程结构是这样的

[牛仔连接进程]->[用户进程]->[房间进程]

所以,如果您使用类似的结构,您可以为每个用户保存一个进程上的用户进程名称,当您需要一个用户的名称时,您只需询问该进程的名称即可

我想说清楚:

您的聊天室模块表示您可能希望分离cowboy初始化并为每个聊天室创建一个进程的所有聊天室 Cowboy连接过程由Cowboy创建并重用。因此,您不能仅将连接进程用作用户。除非您正在进行websocket连接 您必须创建一个名为chat_user的新模块,该模块表示聊天用户并存储其状态的用户级数据。
我希望这能有所帮助。

以下是我要为进入和离开做的事情。我将离开find_user并作为练习发送提示:参见lists:keyfind

handle_cast({enter, Pid, Name}, State = #state{clients= Clients}) ->
    {noreply, State#state{clients = [{Pid, Name} | Clients]}};

handle_cast({leave, Pid}, State = #state{clients = Clients}) ->
    {noreply, State#state{clients  = lists:keydelete(Pid, 1, Clients)}};

是的,你是对的,我想做名称到pid的映射,但是怎么做呢?因为我刚刚开始使用erlang,所以我没有深入的知识。General erlang primer:字典的erlang数据结构:感谢您的回复,正如您在提示中所建议的,我使用了list:keyfind,但每次它都会弹出错误匹配错误。handle_cast{find_user,Pid},State=State{clients=clients}->client=list:keyfindPid,1,clients,io:formatResult:~p,[client],{noreply,State};这是我查找用户的句柄方法,下面是错误消息终止原因=**{{badmatch,{,Moin},[{chat_-room,handle_-cast,2,[{file,src/chat_-room.erl},{line,71}},{gen server,handle_-msg,5,[{file,gen_-server.erl},{line,599},您找到有关此错误的任何信息吗?我从2天开始搜索,但未找到任何有用的信息。请尝试使用client=,而不是client=。Erlang变量必须是大写。Erlang原子是小写。