Elixir:use语句中的动态参数



如何将adapter参数动态传递给Nebulex.Cache模块初始化?

defmodule MyApp.RedisCache do    
use Nebulex.Cache,
otp_app: :nebulex,
adapter: if true do NebulexRedisAdapter else Nebulex.Adapters.Nil end
end

最简单的方法是将条件上移一级。

defmodule MyApp.RedisCache do    
if true do
use Nebulex.Cache,
otp_app: :nebulex,
adapter: NebulexRedisAdapter
else
use Nebulex.Cache,
otp_app: :nebulex,
adapter: Nebulex.Adapters.Nil
end
...
end

另一种方法是创建一个带有参数的私有宏,或者创建一个存储adapter的模块属性并将其传递给use(假设Nebulex.Cache__CALLER__上下文中执行Macro.expand/2自变量)


原因是宏接收AST,所以__using__/1将接收的是quote do: if ....,它甚至不会在第一个编译阶段尝试编译。


下面的代码可能会揭示如何在调用之间传递AST以及Macro.expand/2的作用。

defmodule M do
@param if(true, do: M1, else: M2)
defmacrop t1(arg: args) do
IO.inspect(args, label: "#1")
end
defmacrop t2(arg: args) do
IO.inspect(Macro.expand(args, __CALLER__), label: "#2")
end
def test do
t1(arg: if(true, do: M1, else: M2))
t2(arg: if(true, do: M1, else: M2))
t1(arg: @param)
t2(arg: @param)
end
end

结果是:

#1: {:if, [line: 19],
...
#2: {:case, [optimize_boolean: true],
...
#1: {:@, [line: 21], [{:param, [line: 21], nil}]}
#2: M1

注意,if被扩展为case,并且模块属性没有被扩展,除非对其调用显式Macro.expand/2

最新更新