Elixir GenServer.start_link 抛出异常而不是返回元组

Elixir GenServer.start_link throws exception instead of returning a tuple

我正在玩 GenServer,我在实现自定义 init 回调时遇到了问题。

请考虑以下代码:

defmodule GenS do
  use GenServer

  def start_link(initial \ 0) do
    GenServer.start_link(__MODULE__, initial)
  end

  def init(initial) do
    case initial do
      3 -> {:stop, "Can't initialise with 3"}
      _ -> {:ok, initial}
    end
  end
end

case GenS.start_link(3) do
  {:error, reason} -> IO.puts "Failed with #{reason}"
  {:ok,    _}      -> IO.puts "This has worked!"
end

IO.puts "I'm still alive!"

执行这段代码时,我可以看到输出:

▶ elixir gens.ex
** (EXIT from #PID<0.46.0>) "Can't initialise with 3"

虽然我期待 成功 分支的类似输出(当值不同于 3 作为参数传递时):

▶ elixir gens.ex
This has worked!
I'm still alive!

根据GenServer.start_link/3的文档:

If the init/1 callback fails with reason, this function returns {:error, reason}. Otherwise, if it returns {:stop, reason} or :ignore, the process is terminated and this function returns {:error, reason} or :ignore, respectively.

我希望返回元组,我可以再次匹配,但似乎并非如此。你有什么建议吗?

I'd expect the tuple to be returned, agains which I could patter match, but it seems not to be the case. Do you have any advice?

这里的问题是您将 链接到派生进程并从 init 返回 {:stop, ...} 是向调用进程发送退出信号,这在默认情况下会终止调用进程。

您可以切换到使用 GenServer.start(如果您愿意,稍后可以手动链接进程),或者在开始 GenS 之前通过 运行 捕获退出信号:

Process.flag(:trap_exit, true)

(请注意,这将在 GenS 结束时向调用进程发送一条消息,您可能希望丢弃该消息以防止浪费内存。)

在这两种情况下,我都得到以下输出:

Failed with Can't initialise with 3
I'm still alive!