學習軌道
/
Elixir
Elixir
/
練習
/
抽號碼牌
抽號碼牌

抽號碼牌

學習練習

簡介

行程

在 Elixir 裡,所有的程式碼都在行程中執行。

預設情況下,函式會在呼叫它的同一個行程中執行。當你需要明確地在新行程中執行某個函式時,可以使用spawn/1:

spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>

spawn/1會建立一個新行程,執行指定的零引數函式,並回傳一個_行程識別碼_(PID)。只要函式還在執行,這個新行程就會保持存活,之後再默默結束。

Elixir 的行程不該和作業系統的行程混為一談。Elixir 的行程使用的記憶體和 CPU 少得多。即使 Elixir 應用程式同時執行數百個 Elixir 行程,也完全沒問題。

訊息

行程之間不會直接共用資訊。行程透過_收發訊息_來分享資料。

你可以用send/2把訊息傳送給任何行程。send/2的第一個引數是收件者的 PID,第二個引數是訊息。

訊息可以是任何型態。通常它是由原子和元組組成的。如果你想要收到回應,就應該在訊息中的某處附上傳送者的 PID。你可以用self()取得目前行程的 PID。

send/2不會檢查收件者是否收到了訊息,也不會檢查收件者是否還活著。訊息最後會進到收件者的_信箱_,只有在收件者明確要求_接收訊息_時才會被讀取。

你可以用receive/1巨集從信箱讀取訊息。它接受一個do區塊,可以對訊息進行模式比對。

receive do
  {:ping, sender_pid} -> send(sender_pid, :pong)
  :do_nothing -> nil
end

receive/1會從信箱中取出符合任一給定模式的_一則訊息_,並執行該模式對應的運算式。如果信箱裡沒有訊息,或是信箱中的訊息都不符合任何模式,receive/1就會等待訊息進來。

接收迴圈

如果你想接收不只一則訊息,就需要遞迴地呼叫receive/1。常見的做法是實作一個遞迴函式,例如命名為loop,它會呼叫receive/1、對訊息做點處理,然後再呼叫自己,繼續等待更多訊息。如果你需要在一次receive/1呼叫到另一次之間保留一些狀態,可以透過傳遞引數給那個loop函式來做到。

行程識別碼

行程識別碼是獨立的資料型態。它們的功能就像_信箱地址_,只要你有某個行程的 PID,就可以傳訊息給那個行程。PID 通常是間接產生的,例如spawn這類會建立新行程的函式,其回傳值就是 PID。

說明

你正在為一台號碼牌機撰寫嵌入式系統。這是個非常簡單的機型。它可以發出連續的號碼,並回報最後發出的號碼是多少。

1. 啟動機器

實作 start/0 函式。它應該建立一個新的行程,並回傳該行程的 PID。這個新行程還不需要做任何事。

TakeANumber.start()
# => #PID<0.138.0>

請注意,每次執行這段程式碼時,PID 可能都不一樣。

2. 回報機器狀態

修改這台機器,讓新建立的行程準備好接收訊息(啟動一個receive迴圈),初始狀態為 0。它應該要能接收 {:report_state, sender_pid} 訊息。收到這些訊息時,它應該把目前的狀態(最後發出的號碼牌號碼)傳送給 sender_pid,然後繼續等待更多訊息。

machine_pid = TakeANumber.start()

# a client sending a message to the machine
send(machine_pid, {:report_state, self()})

# a client receiving a message from the machine
receive do
  msg -> msg
end

# => 0

3. 發放號碼

修改這台機器,讓它能接收 {:take_a_number, sender_pid} 訊息。它應該把狀態增加 1,將新的狀態傳送給 sender_pid,然後繼續等待更多訊息。

machine_pid = TakeANumber.start()

# a client sending a message to the machine
send(machine_pid, {:take_a_number, self()})

# a client receiving a message from the machine
receive do
  msg -> msg
end

# => 1

4. 停止機器

修改這台機器,讓它能接收 :stop 訊息。它應該停止等待更多訊息。

5. 忽略非預期的訊息

修改這台機器,讓它在收到非預期的訊息時忽略它,並繼續等待更多訊息。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Elixir Exercism

準備好開始 抽號碼牌 了嗎?

註冊 Exercism,透過 58 個概念168 個練習 和真人引導來學習並精通 Elixir,全部免費。