【问题标题】:Elixir macros, quoting bitstring patternmatch typesElixir 宏,引用位串模式匹配类型
【发布时间】:2017-12-15 19:09:39
【问题描述】:

我正在从事一个项目,我可能会在其中编写大量以下形式的代码:

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}]) 并自动生成必要的结构、typedef 和解包函数,用于固定的任意命名字段尺寸。甚至可以扩展它,在元组中添加第三个字段来传递一个函数来处理可变大小的类型。不幸的是,当我尝试做一个更简单的版本时(只取一个大小的字段,并且只匹配 1):

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

系统告诉我 quote/1 的参数无效。我认为这是因为位串模式匹配中使用的“类型”是一种特殊形式,一般而言,位串文字也是如此,并且这些特定项目不会在其他任何地方使用。

那么,我该如何解决呢?我有十几种打包的结构要解包,每种都有五到二十个不同的字段。如果我不这样做,我可能会求助于 Vim 宏来至少节省我的双手......但这对于维护大量极其重复的代码并没有真正的帮助。

【问题讨论】:

  • 您能发布给出该错误的完整代码吗?第二个 sn-p 对我有用,如果我修正错字(unqote)并在 RHS 上使用二进制(你不能用整数匹配该模式)。
  • ...不,该代码是直接从我测试它的 iex 会话中复制粘贴的。显然,我错过了一个错字。嗯,比较尴尬。正在删除。
  • @Dogbert 我突然想到,即使问题很小,您仍然回答了它。来吧,把它作为回应,我会批准的。

标签: macros elixir unpack special-form


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2017-12-03
    • 2017-03-06
    相关资源
    最近更新 更多