Elixir引用记录(将其转换为元组)并保留数据?

时间:2013-10-30 17:10:15

标签: macros erlang record quote elixir

使用quote do:时引用的记录不会转换为包含记录字段的元组:

 iex(1)> quote do: is_bitstring("blah")
 {:is_bitstring, [context: Elixir, import: Kernel], ["blah"]}
 iex(2)> quote do: Computer.new("Test")
 {{:., [], [{:__aliases__, [alias: false], [:Computer]}, :new]}, [], [[name: "Test"]]}
 iex(3)> quote do: Computer.new("Test")
 {{:., [], [{:__aliases__, [alias: false], [:Computer]}, :new]}, [], [[name: "Test"]]}
 iex(4)> c = Computer.new("Test")
 Computer[name: "Test", type: nil, processor: nil, hard_drives: []]
 iex(5)> c
 Computer[name: "Test", type: nil, processor: nil, hard_drives: []]
 iex(6)> quote do: c
 {:c, [], Elixir}

另外,当我尝试在我的代码中执行此操作时:

defmacro computer([do: code]) do
  # macro login here
  # build computer record based on macro logic
  computer = Computer.new(params)
  quote do: unquote computer
end

我收到错误:

  

**(CompileError)elixir / test / lib / computer_dsl_test.exs:带引号的表达式中的元组必须有2或3个项,无效的引用表达式:Computer [name:“”,type:nil,processor:nil,hard_drives: []]

我认为记录只是具有某种包装函数的元组。 Elixir入门指南说明"A record is simply a tuple where the first element is the record module name."我缺少什么?是否有一个函数我可以调用记录来获取元组表示?我知道raw: true选项,但我不确定如何在现有记录中使用它。

任何见解?

2 个答案:

答案 0 :(得分:6)

记录是元组。您在控制台上看到的输出只是格式化,以便于检查。如果使用raw:true:

检查记录,则可以检查记录是否为元组
iex(1)> defrecord X, a: 1, b: 2

iex(2)> x = X.new
X[a: 1, b: 2]   # This is formatted output. x is really a tuple

iex(3)> IO.inspect x, raw: true
{X, 1, 2}

可以看出,记录实例实际上是一个元组。你也可以在上面进行模式匹配(虽然我不建议这样做):

iex(4)> {a, b, c} = x

iex(8)> a
X

iex(9)> b
1

iex(10)> c
2

你提到的引用完全不同。它将Elixir表达式转换为AST表示,可以将其注入AST的其余部分,最常见的是宏。引用仅在编译时相关,因此,它甚至无法知道变量中的内容。所以当你说:

quote do: Computer.new("Test")

您得到的结果是Computer.new函数调用的AST表示。但此时不调用该函数。

答案 1 :(得分:4)

只是在宏定义中阅读错误消息和灵药“获得陈述”,似乎报价的结果具有以下形式:

  

通常,上面的每个节点(元组)都遵循以下格式:

     

{tuple | atom,list,list |原子}

The first element of the tuple is an atom or another tuple in the same representation;

The second element of the tuple is an list of metadata, it may hold information like the node line number;

The third element of the tuple is either a list of arguments for the function call or an atom. When an atom, 
     

这意味着元组代表一个变量。

     

除了上面定义的节点,还有五个Elixir文字,当引用时返回自己(而不是元组)。他们是:

     

:sum#=>原子

     

1.0#=>编号

     

[1,2]#=>列表

     

“二进制”#=>字符串

     

{key,value}#=>具有两个元素的元组

我的猜测是,unquote是quote的反函数,所以它期望作为参数之一的上述形式。计算机记录不是这种情况。

我认为unquote在那里没有必要(虽然我没有尝试理解你的代码的意图......)和那个

defmacro computer([do: code]) do %% why do you need this argument?
    quote do: Computer.new
end

应该没问题。