資料的不變性 (Immutability)
Elixir是個函數式的程式語言,因此他有一個特性,也就是資料具有不變性。
簡單講就是當一個資料被生成後就無法對其進行修改,只能根據舊資料,去作出一個自己需要的新資料。
若放在變數上,也就是: 一但一個變數綁定資料後,是不可修改其資料內容的,除非重新綁定。
此外函數式編程還具有一些額外的特點,大家可以看以下這個連結了解一下,或是自己找一下資料。
使用JavaScript學習函式編程
Elixir既然是一個函數式的語言,那自然的有更多語言特性是符合FP開發的,其資料的不變性以及Pattern Matching就是其二,此外,為了處理不可變的資料,Elixir所提供的內置函式,都是不會改變資料本身的純函式。
舉個例子:
Map.put用來將Map中新增一個值,但卻不會修改data本身,而是會回傳一個新增後的Map。
iex(1)> data = %{a: 1}
%{a: 1}
iex(2)> Map.put(data, :b, 2)
%{a: 1, b: 2}
iex(3)> data
%{a: 1} # 資料沒變
iex(4)> data = Map.put(data, :b, 2) # 要這樣寫
若是想在一個List中過濾大於10的值,則是用以下的寫法:
iex(1)> data = [1,3,6,8,32,15]
[1, 3, 6, 8, 32, 15]
iex(2)> data = Enum.filter(data, fn x -> x < 10 end)
[1, 3, 6, 8]
以上就是FP的純函式的使用特性,並且不只在Elixir,在JS以及許多程式語言中,這種寫法以及純函式的觀念已經越來越盛行了。
模式比較 (Pattern Matching)
模式比較是Elixir中一個重要的特性,他可以幫助開發者寫出易讀且簡潔的程式碼。
在Elixir中,等號不只是賦值(雖然前面已經用很多次了,但他不只是那樣),在Elixir中,"=" 代表的是模式比較。
簡單講,他會比較等號兩邊的值是否能夠相等,如果能夠相等,便會讓他相等。
以前面的例子來說:
iex(1)> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex(2)> head
1
iex(3)> tail
[2, 3]
或是
iex(1)> [a, 2, c] = [1, 2, 3]
[1, 2, 3]
iex(2)> a
1
iex(3)> c
3
都是模式比較的用法。
但如果是無法進行匹配時,便會報錯,例如:
iex(5)> [a, 2, a] = [1, 2, 3]
** (MatchError) no match of right hand side value: [1, 2, 3]
因為a在一次 matching 中只能重新進行一次綁定
,但沒有任何值可以讓兩邊相等,所以matching失敗。
可使用底線 _ 代替變數,當你不在意他是任何值的時候。
iex(6)> [a, _, _] = [1, 2, "haha"]
[1, 2, "haha"]
iex(7)> a
1
如果你不希望變數被重新綁定,可使用 ^ (pin operator),那不管如何那個變數在這次matching中就不會重新綁定了。
iex(1)> a = 1
1
iex(2)> [^a, 2, 3] = [1, 2, 3]
[1, 2, 3]
iex(3)> a = 2
2
iex(4)> [^a, 2, 3] = [1, 2, 3]
** (MatchError) no match of right hand side value: [1, 2, 3]
或許你會好奇,既然都不要重新綁定了,不會賦值,那為甚麼還要作模式比較,那是因為模式比較除了賦值,也同是能做到"比較",因此有時候也許你的目的不是賦值,而是比較,有時候則是兩者同時。
模式比較配合其他Elixir的語法,可以變出幫助程式碼變得更簡潔易懂,後面章節就會看到。