利用巨集為elixir增加while迴圈控制結構

2021-08-21 02:39:50 字數 3241 閱讀 2108

c語言中的巨集定義:

#define sum(a, b) (a + b)
程式中就可以用sum這個求和函式(相當於符號替換),編譯器會在編譯時將所有出現sum(a, b)的地方替換成(a + b), 它是個預編譯指令,在編譯時執行。其實elixir中的巨集也具有類似的功能,它能為elixir帶來新的特性。比如說elixir中是沒有while迴圈的,如果我們想在elixir中使用while迴圈怎麼辦比如說我想用這樣乙個功能:

while

true

do receive do

"break"-> break

_ -> io.puts "do something else"

endend

輪詢接受訊息,當接收到break的訊息時就退出while迴圈(elixir的迴圈有很多種,關鍵在於這個break,我們需要一種幫助我們提前結束迴圈的能力,又不需要附加很多**,在需要的時候呼叫break就能跳出迴圈這是我們所希望有的,雖然這很不函式式)。接下來就用elixir的巨集來實現這一功能!首先我們需要乙個無限迴圈(elixir中不直接提供不過我們可以使用stream.cycle產生無限流)

for

_<- stream.cycle([:any]) do

nilend

有了無限迴圈我們需要乙個巨集來定義while

defmodule whileloop do

defmacro while(condition_expression, do: do_block) do

quote

dofor _ <- stream.cycle([:any]) do

if unquote(condition_expression) do

unquote(do_block)

else

# break out of loop

end end

endend

end

這裡就用到了quote和unquote,我們定義乙個while巨集判斷條件condition_expression來決定是否執行do_block中的程式結構。我們如何break乙個無限迴圈呢?throw乙個error可不可以?答案是當然可以!

defmodule whileloop do

defmacro while(condition_expression, do: do_block) do

quote

dofor _ <- stream.cycle([:any]) do

if unquote(condition_expression) do

unquote(do_block)

else

break()

endend

endend

def break, do: throw :break

end

我們增加乙個函式break定義,並且在else中呼叫break這樣就能跳出無限迴圈了,但是好像還有乙個問題是不是這樣程式就崩掉了!所以還是要新增乙個容錯try catch,對!

defmodule whileloop do

defmacro while(condition_expression, do: do_block) do

quote

dotry

dofor _ <- stream.cycle([:any]) do

if unquote(condition_expression) do

unquote(do_block)

else

break()

endend

catch :break -> :ok

endend

enddef break, do: throw :break

end

我們把自己throw的break給抓住,這樣系統就不會崩掉了。這裡quote與unquote的配合是很巧妙的,quote的do end結構中的程式結構都會變成符號描述(ast)而不會執行其程式語句結果(保證了do_block程式結構不會在if判斷之前執行,因為while其實是函式condition_expression和逗號後面的都是引數,對比python中的函式帶()和不帶(),fun和fun()乙個會執行乙個是函式的引用,你可以傳進另乙個函式使用),但是我們需要在滿足條件時執行do_block程式結構,因此也需要unquote(do_block),condition_expression同理。好了while迴圈結構也完成了!我們再用開頭的程式試一下while迴圈是否工作正常,來乙個完整的程式!

import whileloop

= task.start fn ->

while

true

do receive do

"break" -> break

_ -> io.puts "do something else"

end end

endprocess.send pid, "hi",

process.send pid, "break",

process.alive? pid

將以上**貼上到iex中(要先載入whileloop模組可以直接貼上進iex shell),可以得到如下執行結果

iex(13)> process.send pid, "hi", 

do something else

:okiex(14)> process.send pid, "hello",

do something else

:okiex(16)> process.alive? pid

true

iex(17)> process.send pid, "break",

:okiex(18)> process.alive? pid

false

在向程序傳送hi和hello訊息後while迴圈還是沒有退出繼續等待接受訊息,但傳送完break後程序也隨之退出說明while迴圈正常break!看來我們的while如預期般的執行了^^,不過此處還是有乙個問題我們並不能在do_block中直接更改condition_expression條件值來達到跳出迴圈,說白了函式式程式語言是不允許你去改變函式引數的。但是while x < y do something這樣的結構還是允許的,用處還是很大的,在很多需要無限迴圈的地方可以節約很多的**。

利用excel為資料批量增加tr td標籤

第一步 準備原始標籤資料格式 第二步 把這些資料調整成一行,這樣方便在excel操作 18 第一列 20 第二列第三步 開啟已經準備好的excel資料格式 第四步 給excel單元格前後新增列 為第五步增加標籤做準備 並把單元格操作區域設定 文字 格式。第五步 為excel資料增加標籤 第六步 拖動...

利用excel為資料批量增加tr td標籤

第一列第二列 第二步 把這些資料調整成一行,這樣方便在excel操作 第一列第二列 第三步 開啟已經準備好的excel資料格式 如圖1 第四步 給excel單元格前後新增列 為第五步增加標籤做準備 並把單元格操作區域設定 文字 格式。如圖2 第五步 為excel資料增加標籤 如圖3 第六步 拖動標籤...

增加專案巨集或bom巨集

1.增加bom巨集 同乙個專案可能不同bom的測試項不同,這時候我們就需要通過bom巨集來實現控制不同bom支援不同測試項的功能。工廠模式決定乙個專案有哪些測試項是在cust.h通過控制巨集的開啟與關閉實現的。但是針對同乙個專案不同bom新增器件,如x609專案 c bom不支援指紋測試項,則需要通...