【问题标题】:Macro block unexpectedly returns [do: return value]宏块意外返回 [do: return value]
【发布时间】:2018-06-10 07:51:19
【问题描述】:

我在宏中有以下定义:

defmacro route(pattern, options \\ [], block) do
  name = "my_fun"
  def unquote(name)(var!(conn)) do
    unquote(block)
  end
end

我正在用这个函数调用宏:

route "/" do
  conn
  |> put_resp_content_type("text/plain")
  |> send_resp(200, "Hello, world!")

内部块返回一个%Plug.Conn{} 结构,但是当我在我的宏中打印unquote(block) 的结果时,我得到[do: %Plug.Conn{}] 我做错了什么? do 关键字列表从何而来?

更大的sn-p

defmacro route(pattern, options \\ [], block) do
  name = Keyword.get_lazy(options, :name, fn -> create_name(pattern, options) end)
  route = {pattern, name}
  quote do
    @routes [unquote(route) | @routes]
    def unquote(name)(var!(conn)) do
      resp = unquote(block)
      IO.puts("outside the block, resp is")
      IO.inspect(resp)
    end
  end
end

route "/" do
  resp = conn
  |> put_resp_content_type("text/plain")
  |> send_resp(200, "Hello, world!")
  IO.puts("Inside the block, resp is")
  IO.inspect(resp)
  resp
end

结果

Inside the block, resp is
%Plug.Conn{
  adapter: {Plug.Adapters.Cowboy2.Conn, :...},
  assigns: %{},
  {....SNIP....}
}

outside the block, resp is
[
  do: %Plug.Conn{
    adapter: {Plug.Adapters.Cowboy2.Conn, :...},
    assigns: %{},
    {....SNIP....}
  }
]

【问题讨论】:

  • 尝试在参数列表中将block 更改为do: block
  • 好的,修复它。后续问题:最初是如何工作的??
  • 这绝对是太晚了,这是有道理的。 unquote([{:do, AST}]) 将返回 [{do:, parse_the_ast(AST)}]。干杯,晚安

标签: macros elixir metaprogramming


【解决方案1】:

您需要将参数从block 更改为do: block

defmacro route(pattern, options \\ [], do: block) do

Elixir 宏调用中的 do ... end 参数作为单项关键字列表传递,键为 :do

如果您不通过将嵌套模式匹配为 do: block 来删除该嵌套,则参数的值将是 [do: block],当您取消引用它时,您将取消引用 [do: ...],这也是一个有效的表达式并解释了为什么您的代码有效以及为什么会打印 [do: ...]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2014-01-08
    • 2019-10-17
    • 2015-08-18
    • 1970-01-01
    • 2020-04-21
    • 2020-12-08
    相关资源
    最近更新 更多