那些讓你更愛 Elixir 的理由
Elixir 的超程式設計能力,擁有和 Lisp 一樣的程式碼即資料的特點。它的方法名,引數和方法體等,能用 List 的資料格式包裝起來,傳給巨集(Macro),再做分析或者擴充套件。且看ofollow,noindex">Programming Elixir ≥ 1.6 書中很簡單的展示程式碼。
defmodule My do defmacro macro(param) do IO.inspect param end end defmodule Test do require My My.macro do 1 + 2 else 3 + 4 end end # => [ do: {:+, [line: 7], [1, 2]}, else: {:+, [line: 9], [3, 4]} ]
IO.inspect
(類似於System.out
或者console.log
) 打印出來的就是巨集接收到的以 List 格式包裝的程式碼。
所以,通過巨集(Macro),我們可以動態生成程式碼,實現 AOP 在方法前後包裝自己的邏輯等。比如下面的程式碼,times_3
和times_4
就是動態生成的方法。
defmodule Times do defmacro times_n(n) do quote do def unquote(:"times_#{n}")(v) do unquote(n) * v end end end end defmodule Test do require Times Times.times_n(3) Times.times_n(4) end IO.puts Test.times_3(4)#=> 12 IO.puts Test.times_4(5)#=> 20
Protocol
“多型”,對於學過面向物件的開發人員來說,應該是一個很熟悉的概念了。單一的介面,不同的型別或實現。
在 JAVA 裡,如果你想實現“多型”,你必須修改那些類的原始碼,讓它們都繼承某個公共類,或者實現某個統一的介面。假如,你想為第三方的一些“多型”類新增一些行為,但你沒辦法修改它的原始碼,這就比較尷尬了。然後各種么蛾子的方法都會弄出來。
但是,Elixir Protocol 的實現方式,可以讓你不必修改對方的原始碼的情況下,實現擴充套件。借Programming Elixir ≥ 1.6 書中的例子來說明一下。
defprotocol Collection do @fallback_to_any true def is_collection?(value) end defimpl Collection, for: [List, Tuple, BitString, Map] do def is_collection?(_), do: true end defimpl Collection, for: Any do def is_collection?(_), do: false end Enum.each [1, 1.0, [1, 2], {1, 2}, %{}, "cat"], fn value -> IO.puts "#{inspect value}:#{Collection.is_collection?(value)}" end # 打印出來的結果就是: 1: false 1.0: false [1, 2]: true {1, 2}: true %{}: true "cat": true
上面就為系統內建的資料型別,定義了一個很簡單的 “多型” 函式,檢測哪些是屬於集合類。嗯,就是這麼簡潔。
Elixir 除了功能強大,學習它還可以給自己一種非常不同的思維方式。如果說 Elixir 有什麼不好,那就是周邊的人少了點吧,Slack Channel 才 2W 多人,遇到問題找答案可就不是那麼容易的事情了。不過,我覺得還是值得的。
最後附上 Joe Armstrong 老爺子,Erlang 作者對 Elixir 的第一印象文章A week with Elixir 。