Elixir宏,引用bitstring patternmatch类型

时间:2017-12-13 02:30:35

标签: macros elixir unpack special-form

我正在开展一个项目,我可能会在其中编写大量代码:

defmodule Kind
  defstruct [name1, name2, name3]
  @type t :: %Kind{name1: integer(), name2: integer(), name3: binary()}
  def unpack(input) do
    with <<name1::integer-8>> <- Enum.take(input, 1),
      <<name2::integer-little-32>> <- Enum.take(input, 4),
      <<name3::binary-10>> <- Enum.take(input, 10),
    do: %Kind{name1: name1, name2: name2, name3: name3>>
  end
end

(对于任意输入名称和类型集,input是一次生成一个字节的二进制流)

能够在宏中处理它是非常有用的,这样我就可以简单地编写(例如)use Unpack quote([{name1, integer-8}, {name2, integer-little-32}, {name3, binary-10}])并自动生成必要的struct,typedef和unpacking函数,用于任意命名字段固定尺寸。甚至可以扩展它,在元组中添加第三个字段以传递函数来处理可变大小的类型。不幸的是,当我尝试做一个更简单的版本时(只采用一个大小的字段,只匹配1):

defmodule Unpack do
  defmacro testmacro({name, kind}) do
    quote do
      <<unquote(name)::unqote(kind)>> = 1
    end
  end
end

系统告诉我它quote/1的参数无效。我认为这是因为&#34;类型&#34;在bitstring模式匹配中使用的是一种特殊形式,一般来说是bittring文字,并且这些特定项目不会在其他任何地方使用。

那么,我该如何解决这个问题呢?我有十几种打包的结构来打开包装,每个包含五到二十个不同的字段。如果我不这样做,我可能会使用Vim宏来至少保存我的手......但这对于维护大量极其重复的代码确实没有帮助。

1 个答案:

答案 0 :(得分:1)

两件事:unquote中有拼写错误,RHS必须是二进制,以便模式匹配。通过这些更改,您的代码适用于我:

defmodule Unpack do
  defmacro unpack({name, kind}) do
    quote do
      <<unquote(name)::unquote(kind)>> = "a"
    end
  end
end

defmodule Main do
  import Unpack

  def main do
    unpack({foo, integer-8})
    IO.inspect foo
  end
end

Main.main

输出:

97