主动从 Elixir 的聊天频道中删除用户
Actively remove user from chat channel in Elixir
我是 Elixir 的初学者,我正在开发一个具有多个频道的简单聊天服务器。
我的频道是一个GenServer
,它存储了一个用户列表(pids),还有一个映射(user ref -> pid)来处理用户进程崩溃(来自Elixir Guides ).但是因为它是一个以 refs 为键的地图,当我实现 remove_member_from_channel
函数时,我想删除 pid(地图的值),我该怎么做呢?还是我选择了错误的实现方式?
defmodule Chat.Channel do
use GenServer
# ......
def add_member(channel, user) do
GenServer.call(channel, {:add_member, user})
end
def remove_member(channel, user) do
GenServer.call(channel, {:remove_member, user})
end
# ......
def handle_call({:add_member, user}, _from, {members, refs}) do
if Enum.member?(members, user) do
{:reply, :already_added, {members, refs}}
else
new_members = [user | members]
ref = Process.monitor(user)
new_refs = Map.put(refs, ref, user)
{:reply, :ok, {new_members, new_refs}}
end
end
def handle_call({:remove_member, member}, _from, {members, refs}) do
if Enum.member?(members, member) do
new_members = List.delete(members, member)
# What to do with refs??
{:reply, :ok, {new_members, refs}}
else
{:reply, :member_not_added, {members, refs}}
end
end
def handle_info({:DOWN, ref, :process, _pid, _reason}, {members, refs}) do
{member, new_refs} = Map.pop(refs, ref)
new_members = List.delete(members, member)
{:noreply, {new_members, new_refs}}
end
end
使用Enum.filter/2
(or Enum.reject/2
:
def handle_call({:remove_member, member}, _from, {members, refs}) do
if Enum.member?(members, member) do
new_members = List.delete(members, member)
new_refs =
Enum.filter(refs, fn
{_ref, ^member} -> false
_ -> true
end)
{:reply, :ok, {new_members, refs}}
else
{:reply, :member_not_added, {members, refs}}
end
end
一般来说,我最好把used_id ⇒ reference
图存起来,像这样:
new_refs = Map.put(refs, user, ref) # or even better used.id
这样一来以后可能会简单地使用 Map.delete/2
:
...
new_members = List.delete(members, member)
new_refs = Map.delete(refs, member) # or member.id
我是 Elixir 的初学者,我正在开发一个具有多个频道的简单聊天服务器。
我的频道是一个GenServer
,它存储了一个用户列表(pids),还有一个映射(user ref -> pid)来处理用户进程崩溃(来自Elixir Guides ).但是因为它是一个以 refs 为键的地图,当我实现 remove_member_from_channel
函数时,我想删除 pid(地图的值),我该怎么做呢?还是我选择了错误的实现方式?
defmodule Chat.Channel do
use GenServer
# ......
def add_member(channel, user) do
GenServer.call(channel, {:add_member, user})
end
def remove_member(channel, user) do
GenServer.call(channel, {:remove_member, user})
end
# ......
def handle_call({:add_member, user}, _from, {members, refs}) do
if Enum.member?(members, user) do
{:reply, :already_added, {members, refs}}
else
new_members = [user | members]
ref = Process.monitor(user)
new_refs = Map.put(refs, ref, user)
{:reply, :ok, {new_members, new_refs}}
end
end
def handle_call({:remove_member, member}, _from, {members, refs}) do
if Enum.member?(members, member) do
new_members = List.delete(members, member)
# What to do with refs??
{:reply, :ok, {new_members, refs}}
else
{:reply, :member_not_added, {members, refs}}
end
end
def handle_info({:DOWN, ref, :process, _pid, _reason}, {members, refs}) do
{member, new_refs} = Map.pop(refs, ref)
new_members = List.delete(members, member)
{:noreply, {new_members, new_refs}}
end
end
使用Enum.filter/2
(or Enum.reject/2
:
def handle_call({:remove_member, member}, _from, {members, refs}) do
if Enum.member?(members, member) do
new_members = List.delete(members, member)
new_refs =
Enum.filter(refs, fn
{_ref, ^member} -> false
_ -> true
end)
{:reply, :ok, {new_members, refs}}
else
{:reply, :member_not_added, {members, refs}}
end
end
一般来说,我最好把used_id ⇒ reference
图存起来,像这样:
new_refs = Map.put(refs, user, ref) # or even better used.id
这样一来以后可能会简单地使用 Map.delete/2
:
...
new_members = List.delete(members, member)
new_refs = Map.delete(refs, member) # or member.id