Elixir - 宏



宏是 Elixir 最高階和最強大的功能之一。與任何語言的高階功能一樣,應謹慎使用宏。它們使在編譯時執行強大的程式碼轉換成為可能。我們現在將簡要了解什麼是宏以及如何在其中使用它們。

引用

在我們開始討論宏之前,讓我們首先看看 Elixir 的內部機制。Elixir 程式可以用它自己的資料結構來表示。Elixir 程式的基本構建塊是一個包含三個元素的元組。例如,函式呼叫 sum(1, 2, 3) 在內部表示為:

{:sum, [], [1, 2, 3]}

第一個元素是函式名,第二個是包含元資料的關鍵字列表,第三個是引數列表。如果您編寫以下內容,可以在 iex shell 中將其作為輸出獲得:

quote do: sum(1, 2, 3)

運算子也表示為這樣的元組。變數也使用這樣的三元組表示,只是最後一個元素是原子,而不是列表。當引用更復雜的表示式時,我們可以看到程式碼是用這樣的元組表示的,這些元組通常以類似樹的結構彼此巢狀。許多語言會將這種表示稱為**抽象語法樹 (AST)**。Elixir 將這些引用的表示式稱為 quoted expressions。

解引用 (Unquote)

既然我們可以檢索程式碼的內部結構,我們如何修改它呢?為了注入新的程式碼或值,我們使用**解引用 (unquote)**。當我們解引用一個表示式時,它將被求值並注入到 AST 中。讓我們考慮一個示例(在 iex shell 中)來理解這個概念:

num = 25

quote do: sum(15, num)

quote do: sum(15, unquote(num))

執行上述程式時,會產生以下結果:

{:sum, [], [15, {:num, [], Elixir}]}
{:sum, [], [15, 25]} 

在 quote 表示式的示例中,它沒有自動將 num 替換為 25。如果要修改 AST,則需要解引用此變數。

既然我們已經熟悉了 quote 和 unquote,我們可以使用宏來探索 Elixir 中的超程式設計。

簡單來說,宏是旨在返回將插入到我們的應用程式程式碼中的引用表示式的特殊函式。想象一下,宏被替換為引用的表示式,而不是像函式一樣被呼叫。使用宏,我們擁有擴充套件 Elixir 並動態地向我們的應用程式新增程式碼所需的一切。

讓我們實現 unless 作為宏。我們將首先使用 `defmacro` 宏來定義宏。請記住,我們的宏需要返回一個引用的表示式。

defmodule OurMacro do
   defmacro unless(expr, do: block) do
      quote do
         if !unquote(expr), do: unquote(block)
      end
   end
end

require OurMacro

OurMacro.unless true, do: IO.puts "True Expression"

OurMacro.unless false, do: IO.puts "False expression"

執行上述程式時,會產生以下結果:

False expression 

這裡發生的事情是我們的程式碼被 `unless` 宏返回的引用程式碼替換了。我們解引用了表示式以在當前上下文中對其求值,還解引用了 do 塊以在其上下文中執行它。此示例向我們展示了在 elixir 中使用宏進行超程式設計。

宏可以用於更復雜的任務,但應謹慎使用。這是因為超程式設計通常被認為是不好的實踐,只有在必要時才應使用。

廣告
© . All rights reserved.