在Agent.start_link / 2中没有匹配的函数子句

时间:2017-08-16 13:35:26

标签: elixir

我想尝试在Supervisor中启动Agent,其中一行用于测试目的:

iex(1)> {:ok, pid} = Supervisor.start_link([{Agent, [fn -> 42 end, name: :test]}], strategy: :one_for_one)

** (EXIT from #PID<0.115.0>) evaluator process exited with reason: shutdown: failed to start child: Agent
    ** (EXIT) an exception was raised:
        ** (FunctionClauseError) no function clause matching in Agent.start_link/2
            (elixir) lib/agent.ex:215: Agent.start_link([#Function<20.99386804/0 in :erl_eval.expr/5>, {:name, :test}], [])
            (stdlib) supervisor.erl:365: :supervisor.do_start_child/2
            (stdlib) supervisor.erl:348: :supervisor.start_children/3
            (stdlib) supervisor.erl:314: :supervisor.init_children/2
            (stdlib) gen_server.erl:365: :gen_server.init_it/2
            (stdlib) gen_server.erl:333: :gen_server.init_it/6
            (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

请注意Supervisor.start_link([{Agent, [fn -> 42 end, name: :test]}], strategy: :one_for_one),此代码向我抛出错误,是否存在语法问题?

我正在使用Elixir 1.5

1 个答案:

答案 0 :(得分:2)

发生这种情况的原因是Supervisor.start_link/2的类型为start_link([:supervisor.child_spec | {module, term} | module], options) :: on_start

根据您传递数据的方式,您似乎正在尝试使用{module, term}term将传递给module的{​​{1}}函数的第一个参数。start_link/2所以,相当于你试图做的是Agent.start_link([fn -> 42 end, name: :test], [])(你可以在错误中看到这一点)。您将所有内容传递给函数的第一个参数,在这种情况下,不允许获取列表。

您将要使用:supervisor.child_spec路径。以下内容应该适合您。

import Supervisor.Spec

children = [
  worker(Agent, [fn -> 42 end, name: :test])
]

opts = [strategy: :one_for_one]
Supervisor.start_link(children, opts)

修改

您刚才在评论中提到您使用的是Elixir 1.5。

您将要创建一个包含Agent行为的模块。

defmodule MyAgent do
  use Agent

  def add(pid, n) do
    Agent.update(pid, fn state -> state + n end)
  end

  def subtract(pid, n) do
    Agent.update(pid, fn state -> state - n end)
  end

  def start_link(fun, opts) do
    Agent.start_link(fun, opts)
  end

  # This function is important because it is how we know how to pass the various options to the actual start_link function.
  def child_spec([fun | rest]) do
    %{
      id: __MODULE__,
      # The fun and rest here are the function we pass in and then the options. Feel free to do this how you want.
      start: {__MODULE__, :start_link, [fun, rest]},
      restart: :permanent,
      shutdown: 5000,
      type: :worker
    }
  end
end

现在调用Supervisor.start_link([{My Agent, [fn -> 42 end, name: :test]}], strategy: :one_for_one)应该返回{:ok, pid}