iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0

因為在 Elixir 裡,所有的值都是不可變的 (immutable)
所以並沒有這種在其他語言常見的迴圈

# 在 elixir 裡沒有這種:
for(i = 0; i < sizeof(array); i++) {
  array[i] = array[i] * 2;
}

所有像是迴圈的,例如上一篇的 for, Enum.map 等,底下也是都是遞迴

要把一個 list 的所有項目都乘二
方便的 map 作法

list = [1,3,5,7,9]
Enum.map(list, fn x -> x * 2 end)

最有彈性的函式遞迴作法

def x2(list), do: x2(list, [])
def x2([], accu), do: Enum.reverse(accu)
def x2([x | tail], accu), do: x2(tail, [x * 2 | accu])

這種剛開始寫的時候會有點不自然
我們一步步的看每次呼叫的情況

剛開始我們呼叫 x2 函數並給參數 [1,2,3,5,7,9]

x2([1,3,5,7,9])

因為只有一個參數,所以會批配到第一個 def x2(list), do: x2(list, [])
這個函式會幫我們加上 accumulator (累積器)到第二個變數後再次呼叫
(在這個例子,accumulator 就是一個空 list,準備接收我們乘過的結果)

x2([1,3,5,7,9], [])

這次因為第一個參數不是空 list,
所以批配到第三個函式 def x2([x | tail], accu), do: x2(tail, [x * 2 | accu])

在這邊第一個變數的值 [1,3,5,7,9]
被 pattern matching 成 [1 | [3, 5, 7, 9]]
並準備呼叫 x2(tail, [x * 2 | accu])
帶入變數變成 x2([3, 5, 7, 9], [1 * 2 | []])

這時候的狀態是 x2([3, 5, 7, 9], [2])
可以看到,原本在前面的 1 已經乘過了,加到 accumulator 裡面
再次呼叫會變成 x2([5, 7, 9], [6, 2])
在一次會變成 x2([7, 9], [10, 6, 2])
直到第一個參數變成空 list x2([], [18, 14, 10, 6, 2])
這個時候會 pattern matching 的是第二個函式 def x2([], accu), do: Enum.reverse(accu)

這時候我們得到的 accu 其實是相反的,因為在 Elixir 裡面從 head 放新項目比較快
所以最後要幫 accu 轉正 Enum.reverse([18, 14, 10, 6, 2])
便得到結果 [2, 6, 10, 14, 18]


上一篇
Comprehensions (推導式) (for)
下一篇
尾遞迴最佳化 (Tail Call Optimization)
系列文
通勤看手機就可讀懂的 Elixir 語言入門教學30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言