继续Elixir文档中的Binding and unquote fragments示例......
我们有一个基于关键字列表定义函数的宏。
defmodule MacroFun do
defmacro defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
end
defmodule Runner do
require MacroFun
kv = [foo: 1, bar: 2]
MacroFun.defkv(kv)
end
Runner.foo
现在让我们将宏的主体移动到辅助函数。
defmacro defkv(kv) do
_defkv(kv)
end
defp _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
太棒了,一切都还行。但是现在如果我们想要在将kv
传递给私有帮助函数之前创建另一个修改 defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
_defkv(modified_kv)
end
end
的宏,那该怎么办呢?
_devkv
这不起作用。 Elixir说 defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
MacroFun._defkv(modified_kv)
end
end
没有定义。我们可以使用完全限定的函数名来修复:
MacroFun._defkv
然后Elixir抱怨_devkv
是私人的。所以我们将其更改为公开,但仍然无法正常工作,因为帮助方法def_modified_kv
会将引用的代码返回到我们引用的宏defmodule MacroFun do
defmacro defkv(kv) do
_defkv(kv)
end
defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
MacroFun._defkv(modified_kv) |> Code.eval_quoted([], __ENV__) |> elem(0)
end
end
def _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
end
!
所以我们可以通过eval来帮助修复辅助函数返回的代码(最终代码):
Code.eval_quoted
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
ViewConfiguration config = ViewConfiguration.get(getActivity());
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if (menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (Exception e) {
e.printStackTrace();
}
setHasOptionsMenu(true);
}
?我觉得我做错了什么。
感谢您的帮助。
答案 0 :(得分:0)
导入模块时,只能导入公共方法。
宏是一个编译时功能,它们在模块中实际写入代码(或AST)。因此,当宏扩展时,宏的上下文就是你调用/使用它的地方。因此,如果您使用宏(未定义)SomeOtherModule
这是宏扩展的上下文。在SomeOtherModule
中,您需要import MacroFun
在本地调用其功能。
以下代码适用于Elixir> = 1.2.0
E.g。
defmodule MacroFun do
defmacro defkv(kv) do
_defkv(kv)
end
defp _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
defmacro def_modified_kv(kv) do
quote bind_quoted: [kv: kv] do
modified_kv = Enum.map kv, fn {k, v} -> {k, v + 1} end
defkv(modified_kv)
end
end
end
defmodule Runner do
import MacroFun
kv = [foo: 1, bar: 2]
def_modified_kv(kv)
end
希望这能回答你的问题!祝你好运。
更新了几次,因为宏有点令人困惑!
答案 1 :(得分:0)
1)通过使用require
,您已告诉编译器编译并提供MacroFun
的公共宏和函数。请注意,无论如何都可以使用这些功能:
请注意,通常在使用前不需要模块,唯一的 例外是如果你想使用模块中的宏。
2)他们可以通过他们的FQN
获得3)这是我的看法:
defmodule MicroFun do
defmacro defkv(kv) do
_defkv(kv)
end
defp _defkv(kv) do
quote bind_quoted: [kv: kv] do
Enum.each kv, fn {k,v} ->
def unquote(k)(), do: unquote(v)
end
end
end
defmacro modifier(kv) do
quote bind_quoted: [kv: kv] do
Enum.map kv, fn {k,v} -> {k, v+1} end
end
end
end
defmodule Runner do
require MicroFun
[foo: 1, bar: 2]
|> MicroFun.modifier
|> MicroFun.defkv
end
我们的想法是,只需管道它们就不需要嵌套宏/函数。