我有一个伞应用程序,
在一个应用程序中(例如: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
我的问题是:
该函数是否实际在App1
或App2
中执行(在哪里定义)?
答案 0 :(得分:2)
如果您要执行此类操作,则会在App1
中执行,但App2
中将评估。< / p>
让我们来看看这实际意味着什么。假设我们有以下模块:
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
之前必须对其进行评估。答案 1 :(得分:1)
此示例将抛出CompileError,因为Capture运算符假定您将提供函数,如下所示:
&Mod.fun/arity
&local/arity
或者至少你将使用Capture运算符指定一个参数,例如。 &Mod.fun(&1)
。
在这种情况下,你的论点是错误的。 如果没有Capture操作符并使用常规方法制作匿名函数,您将拥有:
fn -> Io.puts(Project.get.project[:app]) end
因此它适用于Project.get.project[:app]
的内容。我不熟悉那个花哨的模块,但它应该在你调用它的模块中工作。
答案 2 :(得分:1)
要控制项目执行功能,您可以使用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"
一般来说,在函数之间传递lambdas将保留定义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字典中。