【问题标题】:elixir define dynamic functions inside macro长生不老药在宏内定义动态函数
【发布时间】:2017-05-20 11:17:51
【问题描述】:

我正在尝试在 defmacro 中动态定义函数,但不明白为什么函数值在函数本身内部不可用

defmacro __using__(_) do
  Enum.each ~w(public private), fn value ->
    def unquote(:"make_#{value}")(user = %User{}) do
       %{user | privacy: value}
    end
  end
end

Elixir默认扩展valuevalue()然后说没有这个功能

【问题讨论】:

    标签: elixir


    【解决方案1】:

    您在def 周围缺少quote。您还需要取消引用 def 内的 Map 更新表达式中的值。最后,您需要在这里使用Enum.map 而不是Enum.each,以便__using__/1 返回构造的AST:

    defmacro __using__(_) do
      Enum.map ~w(public private), fn value ->
        quote do
          def unquote(:"make_#{value}")(user = %User{}) do
            %{user | privacy: unquote(value)}
          end
        end
      end
    end
    

    测试:

    defmodule User do
      defstruct [:privacy]
    end
    
    defmodule A do
      defmacro __using__(_) do
        Enum.map ~w(public private), fn value ->
          quote do
            def unquote(:"make_#{value}")(user = %User{}) do
              %{user | privacy: unquote(value)}
            end
          end
        end
      end
    end
    
    defmodule B do
      use A
    end
    
    iex(1)> %User{} |> B.make_public
    %User{privacy: "public"}
    

    编辑:在 cmets 中请求更改:

    defmacro __using__(_) do
      Enum.map ~w(public private), fn value ->
        quote do
          def unquote(:"make_#{value}")(user = %User{}) do
            %{user | privacy: unquote(value)}
          end
          def unquote(:"make_#{String.upcase(value)}")(user = %User{}) do
            %{user | privacy: unquote(String.upcase(value))}
          end
        end
      end
    end
    
    iex(1)> %User{} |> B.make_public
    %User{privacy: "public"}
    iex(2)> %User{} |> B.make_PUBLIC
    %User{privacy: "PUBLIC"}
    iex(3)> %User{} |> B.make_private
    %User{privacy: "private"}
    iex(4)> %User{} |> B.make_PRIVATE
    %User{privacy: "PRIVATE"}
    

    【讨论】:

    • 但是如果我需要添加更多函数到与动态生成的def相同的级别怎么办?
    • 你可以在quote里面放任意数量的def
    • 问题是__using__函数需要一个AST定义列表,所以如果我声明多个quote,那么只有最后一个被使用。
    • 我不确定我是否遵循。我编辑的答案是否符合您的要求?
    • @Dogbert 一个简单的问题:使用Enum.map 返回的值是引用函数定义的列表。这被插入到调用模块中。它定义了函数吗?带引号的列表就是列表本身,但是否意味着编译器会执行每个元素,所以定义了函数?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    相关资源
    最近更新 更多