1. 程式人生 > >[Erlang 0112] Elixir Protocols

[Erlang 0112] Elixir Protocols

Why Elixir

     為什麼要學習Elixir?答案很簡單,為了更好的學習Erlang.這麼無厘頭的理由?

     Erlang語法設計幾乎沒有考慮過取悅開發者,所以學習之初的門檻略高.對於已經克服了最初語法障礙的同學,Elixir其實沒有什麼吸引力. 在Elixir之前已經有很多類似的專案,比如http://lfe.github.io Elixir類似思路的還有http://reia-lang.org 在前,但Elixir顯然做得更好一些.看這些語言的時候,會有一種感覺:把這語言語法層面做優化調整,理想狀態就是Erlang的樣子吧!

     那為什麼要投入時間到Elixir? 深入Elixir內部,可以看到很多非常棒的設計,這些設計並不陌生,之前散見於各種開源專案.不過現在Elixir將這些解決方案整合在一起,而且更具有系統性.對我來說,這是一個很好的切入點.對於很多Ruby開發者來講,Elixir具有很強的語法親和力,而這點對我來講沒有什麼意義,其實我反倒覺得Elixir在語法層面複雜了很多,需要"記住"的規則比較多,而Erlang這方面要精簡很多.

多型

   維基百科上對多型的定義 polymorphism is the provision of a single interface to entities of different types. [Link]對不同型別的資料實體提供一致的處理介面,對於這個定義有很多實現方式,比如介面,泛型.在Elixir提到多型的時候,是這樣描述的:
       Elixir also provides first-class support for pattern matching, polymorphism via protocols (similar to Clojure's), aliases and associative data structures (usually known as dicts or hashes in other programming languages).
也就是說它使用了類似Clojure Protocol的機制實現多型,那我們先看看Clojure裡面的Protocol是怎樣的:
(ns elixir-demo )

(defprotocol  Concatenatable
  (cat [this other]))

(extend-type java.util.List
   Concatenatable
    (cat [this other]
      (concat this other)) )

(extend-type String
  Concatenatable
  (cat [this other]
    (.concat this other)) )

(println
   (cat [1,2,3,4] [5,6,7]))

(println
   (cat "Hello " "World!!!!" ))
輸出結果:
(1 2 3 4 5 6 7) Hello World!!!! 這個,我們在C#中可以找到形式上非常類似的東西,看一個例子:
public static class TypeExtensions
    {
        public static void Dump(this int num)
        {
            Console.WriteLine(string.Format("The int number is :{0} \r\n ", num));
        }

        public static void Dump(this double num)
        {
            Console.WriteLine(string.Format("The float number is :{0} \r\n ", num));
        }

        public static void Dump<T>(this IEnumerable<T> items)
        {
            StringBuilder sb = new StringBuilder("Data:");

            foreach (var item in items)
            {
                sb.AppendFormat("{0}\n", item);
            }
            Console.WriteLine(sb.ToString());
        }
    }
呼叫的程式碼:
 static void Main(string[] args)
        {
            12.Dump();
            (12.23).Dump();
            (new List<string>() { "123", "ok", "test" }).Dump<string>();

            Console.ReadLine();
        }
defprotocol String.Chars do
  def to_string(thing)
end
定義了protocol之後,下面就要按照各種型別做首先,下面擷取的程式碼是針對integer和float的處理:
defimpl String.Chars, for: Integer do
  def to_string(thing) do
    integer_to_binary(thing)
  end
end

defimpl String.Chars, for: Float do
  def to_string(thing) do
    iolist_to_binary(:io_lib_format.fwrite_g(thing))
  end
end
呼叫的時候,對於沒有實現的情況
iex(8)> to_string([1,2])
<<1, 2>>
iex(9)> to_string(:a)  
"a"
iex(10)> to_string(12.3)
"12.3"
iex(11)> to_string(12) 
"12"
iex(12)> to_string({1,2})
** (Protocol.UndefinedError) protocol String.Chars not implemented for {1, 2}
    /data2/src_elixir/elixir/lib/elixir/lib/string/chars.ex:3: String.Chars.impl_for!/1
    /data2/src_elixir/elixir/lib/elixir/lib/string/chars.ex:17: String.Chars.to_string/1
可以限定的資料型別有:Record,Tuple,Atom,List,BitString,Integer,Float,Function,PID,Port,Reference,Any {ok,"今天先到這裡"} 最後小圖一張,2013大事記: