Quote , quote and Macro
1 引用与去引用
elixir可以被自己的数据结构表示出来。在这一章,我们将会学习到这种数据结构是怎样子的,该如果去撰写它们。这一章的学习跟宏
有关,下一章我们将会更深入的学习。
1.1 引用
elixir代码块用三元素的元祖来表示。列如sum(1, 2, 3)
函数调用,内部可以表示为:
{:sum, [], [1, 2,3]}
我们可以通过使用引用
宏来获取到任何表达式的表示:
iex(1)> quote do: sum(1, 2, 3)
{:sum, [], [1, 2, 3]}
iex(2)>
第一项是函数的名字,第二项是一个包含了元数据的keyword
列表,第三项是参数列表。
操作符也可以表示为这样的元组:
iex(2)> quote do: 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}
iex(3)>
map
表示为%{}
的调用
iex(3)> quote do: %{1 => 2}
{:%{}, [], [{1, 2}]}
iex(4)>
变量也可以使用这样的三元组表示,处了最后一个元素是一个原子,而不是列表,其他都一样:
iex(4)> quote do: x
{:x, [], Elixir}
iex(5)>
当引用更加复杂的表达式时,我们可以看到,这些代码是这样的三元组,他们彼此嵌套,结构就好像一棵树。很多语言把他们叫做语法树(AST)。Elixir
把他们称为引用用的表达式。
iex(5)> quote do: sum(1, 2 + 3, 4)
{:sum, [], [1, {:+, [context: Elixir, import: Kernel], [2, 3]}, 4]}
iex(6)>
大体上,这些结构的格式如下:
{ tuple | atom, list, list | atom }
- 第一个元素是一个原子或者是另一个同样表示方式的元祖;
- 第二个元素是一个
keyword
列表,这个歌列表包含了元数据,好像数字和上下文; - 第三个元素要么是一个函数的参数列表要么是一个原子。当这个元素是一个原子时,它表示这个元组是一个变量。
Besides the tuple defined above, there are five Elixir literals that, when quoted, return themselves (and not a tuple). They are:
:sum #=> Atoms
1.0 #=> Numbers
[1, 2] #=> Lists
"strings" #=> Strings
{key, value} #=> Tuples with two elements
很多Elixir
代码都直接翻译成他们的底层引用表达式。我么建议你去尝试不同代码例子来看一下他们的结果是怎样子的。例如,String.upcase("foo")
会展开成什么样?我们也学习到if(true, do: :this, else: :that)
和if true do :this else :that end
是一样的。
Unquoting
引用就是用来检索一个特殊的代码块的内部表示方式。然而,有时候,必须要把一些其他的特定的代码快插入到我们要检索的表示中。
例如想象一下,你有一个变量number
,这个数字你想要把它插入到一个引用的表达式中去。可以使用unquote
把这个数字填入到quoted representation
中。
iex(6)> number = 3
3
iex(7)> Macro.to_string(quote do: 11 + unquote(number))
"11 + 3"
iex(8)>
去引用可以注入到函数名中:
iex(10)> fun = :hello
:hello
iex(11)> Macro.to_string(quote do: unquote(fun)(:word))
"hello(:word)"
iex(10)> fun = :hello
:hello
iex(12)> quote do: unquote(fun)(:word)
{:hello, [], [:word]}
iex(13)>