【问题标题】:How can I pass functions to the macros in elixir?如何将函数传递给 elixir 中的宏?
【发布时间】:2016-09-03 14:43:30
【问题描述】:

used 时,我正在开发一个扩展其他模块功能的模块。问题是有时我想在模块定义中编写一些用于增强模块功能的自定义代码:

所以,它看起来像:

defmodule Included do
  defmacro __using__(_) do
    quote unquote: false do
      # a lot of code
      model
      |> unquote(@callback)
      |> another_bunch_of_things_in_pipe
    end
  end
end

还有我的模块

defmodule Poor do
  use Included

  @callback fn(model) -> %{ model | poor: true } end
end

毫不奇怪,我有一个invalid quoted expression: #Function<0.100338 in file:web/models/user.ex>。我发现 Jose Valim 提到不可能取消引用匿名函数。

那么,您能介绍一下在 elixir 中将自定义代码传递和调用到宏中的好方法吗?

【问题讨论】:

    标签: elixir ecto


    【解决方案1】:

    quotePoor 模块的上下文中运行,因此您不需要取消引用模块属性。但是,@callback 保留供内部使用,因此您需要使用不同的名称:

    defmodule Included do
      defmacro __using__(_) do
        quote do
          @callback_fun.()
        end
      end
    end
    
    defmodule Poor do
      @callback_fun fn -> IO.puts "hello from callback" end
      use Included
    end
    

    你也可以将函数作为参数传递给use,我认为这样更简洁一些,因为它直接显示了函数的使用位置:

    defmodule Included do
      defmacro __using__(opts) do
        fun = Keyword.get(opts, :callback)
        quote bind_quoted: [fun: fun] do
          fun.()
        end
      end
    end
    
    defmodule Poor do
      use Included, callback: fn ->
        IO.puts "hello from callback"
      end
    end
    

    【讨论】:

      【解决方案2】:

      您的代码有几个问题(除了缺少 endfn 这可能是一个错字):

      • @callback 是 Elixir 中的一个特殊属性。你可以阅读更多关于它的信息here。您必须使用其他名称。

      • 给模块属性赋值的语法是@attr value,而不是@attr = value

      • 你不需要unquote属性,你可以直接输入@attr.()

      • 由于__using__一调用use就会被调用,所以你需要在调用use之前声明属性。

      这是固定版本:

      defmodule Included do
        defmacro __using__(_) do
          quote do
            model = %{poor: false}
            model
            |> @back.()
            |> IO.inspect
          end
        end
      end
      
      defmodule Poor do
        @back fn(model) -> %{ model | poor: true } end
        use Included
      end
      

      输出:

      %{poor: true}
      

      【讨论】:

        猜你喜欢
        • 2020-07-17
        • 2018-02-05
        • 1970-01-01
        • 2018-05-16
        • 2014-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多