【问题标题】:Using the capture operator in an umbrella app - elixir在伞形应用程序中使用捕获运算符 - elixir
【发布时间】:2017-09-23 19:46:53
【问题描述】:

我有一个雨伞应用,
在一个应用程序(例如:App1)中,我将一个函数作为参数发送到另一个应用程序(例如:App2)中的另一个函数。
我正在发送这样的功能:

defmodule App1.Bar do
  def bar_bar(fun) do
    fun.()
  end
end

defmodule App2.Foo do
  def foo_foo do
    App1.Bar.bar_bar(&Io.puts(Project.get.project[:app]))
  end
end

我的问题是:
该函数实际上是在App1App2(定义它的地方)中执行的吗?

【问题讨论】:

  • 这可能是错字,因为你调用App2.Bar的函数不是来自App1.Bar
  • @PatNowak,谢谢,已编辑

标签: elixir


【解决方案1】:

如果您要执行此类操作,它将在App1执行,但将在App2评估

让我们来看看这实际上意味着什么。假设我们有以下模块:

defmodule Foo do
  def foo(fun) do
    IO.puts "I AM IN FOO"
    fun.()
  end
end
defmodule Bar do
  def bar(), do: Foo.foo(fn -> IO.inspect baz() end)
  defp baz(), do: "baz"
end

iex(1)> Bar.bar()
I AM IN FOO
"baz"
"baz"

这里需要注意的两个重要部分是:

  • 在匿名函数中看到打印之前,我们打印了I AM IN FOO。这意味着函数在Foo中执行。
  • 我们能够评估Bar.baz/0,即使Foo 无法看到该函数(它也没有自己的baz/0 函数)。这意味着它必须在传递给 Foo.foo/1 之前进行评估。

【讨论】:

    【解决方案2】:

    此示例将抛出 CompileError,因为 Capture 运算符假定您将提供函数,如下所示:

    &Mod.fun/arity
    &local/arity
    

    或者至少您将使用 Capture 运算符为此指定一个参数,例如。 &Mod.fun(&1).

    在这种情况下,您的论点是错误的。 如果没有 Capture 运算符并使用常规方式制作匿名函数,您将在那里:

    fn -> Io.puts(Project.get.project[:app]) end
    

    所以它适用于Project.get.project[:app] 的内容。我不熟悉那个花哨的模块,但它应该可以在你调用它的那个模块中工作。

    【讨论】:

    • 当我按照你的建议 fn -> Io.puts(Project.get.project[:app]) end 时,哪个应用程序正在运行?
    • 运行这个功能的 App2。
    【解决方案3】:

    要控制某个函数在其中执行的项目,可以使用Mix.Project.in_project/4

    Mix.Project.in_project :my_app, "/path/to/my_app", fn module ->
      "Mixfile is: #{inspect module}"
    end
    #=> "Mixfile is: MyApp.Mixfile"
    

    通常,在函数之间传递 lambda 将保留定义 lambda 的词法范围。

    然而,在进程之间传递 lambda 会导致 self() 评估为不同的值:

    iex(10)> lambda = fn -> IO.puts("Lambda running in: #{inspect(self())}") end
    #Function<20.52032458/0 in :erl_eval.expr/5>
    
    iex(11)> lambda.()
    Lambda running in: #PID<0.80.0>
    :ok
    
    iex(12)> spawn(lambda)
    Lambda running in: #PID<0.96.0>
    #PID<0.96.0>
    

    这可以更改依赖于当前 Process 字典的任何内容的输出,例如 Ecto.Repo 在事务中将当前连接存储在 Process 字典中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多