Elixir並非是OOP的語言,因此他沒有物件的概念,所以自然也不會有方法。
在JS裡,各種基本型別都被包裝成了有許多內建方法的物件,因此可以寫出類似這樣的寫法:
result = arr
.map((item) => {
return xxx;
})
.filter((item) => {
return xxx;
})
.join();
這種寫法可以簡潔又簡單的表達出程式的功能,也不會有過於多餘的程式碼。
雖然Elixir並沒辦法用方法不斷的接下去,但它支援一種叫做管線運算子的寫法:
arr = [
%{name: "jack", age: 24},
%{name: "andy", age: 27},
%{name: "tom", age: 18}
]
arr
|> Enum.filter(fn item -> item.age > 20 end)
|> Enum.map(fn item -> "#{item.name} is #{item.age} years old" end)
|> Enum.join(" AND ")
|> IO.inspect
"jack is 24 years old AND andy is 27 years old"
可以把 |>
想像成一個水管,arr被導到Enum.filter的第一個參數,而第二個參數式一個匿名函式,所以實際上是像這樣子:
Enum.filter(arr, fn item -> item.age > 20 end)
然後上式的輸出會再被導到下一個函式中,以此類推,所以上面那串如果不用管道,原本可能是長這樣:
result = Enum.filter(arr, fn item -> item.age > 20 end)
result = Enum.map(result, fn item -> "#{item.name} is #{item.age} years old" end)
result = Enum.join(result, " AND ")
IO.inspect(result)
簡單講,管道 |>
可以將它前面的表達式或是函式的輸出導到它後面的函式中,而多半好用的函式,已經被包裝成許多好用的模組了,因此我們需要做的,不是去看現在的物件有哪些方法(method)可以使用,而是去看我們現在的資料型態要做甚麼處理,應該去哪個模組才有我們所需要的函式。
再配合匿名函式章節提到的匿名函式的簡潔寫法,就可以將上面的程式進一步簡化:
arr
|> Enum.filter(&(&1.age > 20))
|> Enum.map(&("#{&1.name} is #{&1.age} years old"))
|> Enum.join(" AND ")
|> IO.inspect
"jack is 24 years old AND andy is 27 years old"
至於哪些函式好用呢,因為elixir有太多太多的函式,可以應付非常多的情況,但要熟悉這些模組函式還是需要時間的,而我比較熟悉的還是一些比較基本常用的的Enum.map、Enum.filter、Enum.each、Enum.reduce...等。
個人推薦可以到codewars上去用elixir寫一些題目,並且可以參考一下其它大神的寫法,可以慢慢的學到有怎樣的思考方式和有哪些模組比較常用,或是有所妙用。
另外,再想找到某些函式時,最有效的方式還是去官方的文件裡找相關模組的函式說明。
之後進入實作前預計會簡單整理一兩篇比較可能會常用的模組函式的整理。
當作熱熱身(拖篇數?!)
"(一直點下去)這種寫法可以簡潔又簡單的表達出程式的功能,也不會有過於多餘的程式碼"
是說想來討論一下,其實我認為用 pipe operator 是個比一直點下去優秀得多的寫法。你看連 JS TC39 都想要引進 pipe operator了。他們之間的差異,在於前者的每個點,都依賴上一步回傳值的型別,才能決定下一步能夠 .
什麼。如果中間任何一步出現非陣列,那麼你就不能 map, filter, reduce 下去了。如果任何一步可能會出現 nil,那麼就一定要停下來用變數接,否則就會出錯了。
而 pipe operator 就是個單純的函式呼叫,只是位置調換而己,所以你可以一直接續下去。
範例的話,你可以看一下我寫的這篇。(不過這系列很快就要離開 Elixir 了 XD)
https://ithelp.ithome.com.tw/articles/10244624
感謝補充
雖然只是單純的函式呼叫,但在各種漂亮語法的配合下,我自己也是覺得pipeline這種寫法更加讓我喜歡。