How to create a dynamic function name using Elixir macro?

前端 未结 3 1024
忘掉有多难
忘掉有多难 2020-12-30 19:12

I want to create a function names dynamically. I wrote this macro

defmacro generate_dynamic(name) do
  quote do 
    def add_(unquote(name)) do
    end
  end         


        
相关标签:
3条回答
  • 2020-12-30 19:36

    I did this same sort of thing in a gist to try and mimic Ruby's attr_accessor:

    defmodule MacroExp do
      defmacro attr_accessor(atom) do
        getter = String.to_atom("get_#{atom}")
        setter = String.to_atom("set_#{atom}")
        quote do
          def unquote(getter)(data) do
            data |> Map.from_struct |> Map.get(unquote(atom))
          end
          def unquote(setter)(data, value) do
            data |> Map.put(unquote(atom), value)
          end
        end
      end
    
      defmacro attr_reader(atom) do
        getter = String.to_atom("get_#{atom}")
        quote do
          def unquote(getter)(data) do
            data |> Map.from_struct |> Map.get(unquote(atom))
          end
        end
      end
    end
    
    
    defmodule Calculation do
      import MacroExp
      defstruct first: nil, second: nil, operator: :plus
    
      attr_accessor :first   # defines set_first/2 and get_first/1
      attr_accessor :second  # defines set_second/2 and get_second/1
      attr_reader :operator  # defines set_operator/2 and get_operator/1
    
      def result(%Calculation{first: first, second: second, operator: :plus}) do
        first + second
      end
    end
    

    https://gist.github.com/rcdilorenzo/77d7a29737de39f0cd84

    0 讨论(0)
  • 2020-12-30 19:41

    Sometimes, as a useful shortcut, you can achieve the same result inline, without writing a macro using an unquote fragment.

    defmodule Hello do
      [:alice, :bob] |> Enum.each fn name ->
        def unquote(:"hello_#{name}")() do
          IO.inspect("Hello #{unquote(name)}")
        end
      end
    end
    
    Hello.hello_bob    # => "Hello bob"
    Hello.hello_alice  # => "Hello alice"
    
    0 讨论(0)
  • 2020-12-30 19:53

    To achieve this, you can prepend :add_ to the name before unquoting. Also, the parentheses after the method name in this case are required to prevent ambiguities. This should do the trick:

    defmacro generate_dynamic(name) do
      quote do 
        def unquote(:"add_#{name}")() do
          # ...
        end
      end
    end
    
    0 讨论(0)
提交回复
热议问题