Erlang 和 Elixir的差別

原文: http://elixir-lang.org/crash-course.htmlhtml

函數調用

Elixir容許你調用函數的時候省略括號, Erlang不行.git

Erlang Elixir
some_function(). some_function
sum(A,B) sum a,b

從模塊中調用一個函數, 使用不一樣的語法, 在Erlang, 你能夠寫:github

lists:last([1,2]).

從List模塊中調用last函數. 在Elixir中使用.符號代替:符號.正則表達式

List.last([1,2])

注意. 由於Erlang模塊以原子的形式標識, 你能夠在Elixir中以以下方式調用Erlang函數.express

:lists.sort [1,2,3]

全部Erlang內置函數存在於:erlang模塊中.segmentfault

數據類型

原子

在Erlang中, 原子是以任意小寫字母開頭的標識符號. 例如oktupledonut. 大寫字母開頭的任意標識被做爲變量名稱.app

Erlangless

im_an_atom.
me_too.
Im_a_var.
X = 10.

Elixiride

:im_an_atom :me_too im_a_var x = 10 Module # 原子別名, 擴展爲:`Elixir.Module`

還能夠建立非小寫字母開頭的原子, 兩種語言的語法差別以下:函數

Erlang

is_atom(ok). %=> true is_atom('0_ok'). %=> true is_atom('Multiple words'). %=> true is_atom(''). %=> true

Elixir

is_atom :ok #=> true is_atom :'ok' #=> true is_atom Ok #=> true is_atom :"Multiple words" #=> true is_atom :"" #=> true

元組

元組的語法兩種語言相同, 但API有卻別.

列表和二進制

Erlang

is_list('Hello'). %=> false is_list("Hello"). %=> true is_binary(<<"Hello">>). %=> true

Elixir

is_list 'Hello' #=> true is_binary "Hello" #=> true is_binary <<"Hello">> #=> true <<"Hello">> === "Hello" #=> true

Elixir string 標識一個UTF-8編碼的二進制, 同時有一個String模塊處理這類書籍.
Elixir假設你的源文件是以UTF-8編碼的. Elixir中的string是一個字符列表, 同時有一個:string模塊處理這類數據.

Elixir 支持多行字符串(heredocs):

is_binary """ This is a binary spanning several lines. """ #=> true

關鍵字列表

包含兩個元素的元組列表

Erlang

Proplist = [{another_key, 20}, {key, 10}]. proplists:get_value(another_key, Proplist). %=> 20

Elixir

kw = [another_key: 20, key: 10] kw[:another_key] #=> 20

Map

Erlang

Map = #{key => 0}. % 建立Map Updated = Map#{key := 1}. % 更新Map中的值 #{key := Value} = Updated. % 匹配 Value =:= 1. %=> true

Elixir

map = %{:key => 0} # 建立Map map = %{map | :key => 1} # 更新Map中的值 %{:key => value} = map # 匹配 value === 1 #=> true

注意:

1.key: 和 0之間必定要有一個空格, 以下:

iex(2)> map = %{key:0} **(SyntaxError) iex:2: keyword argument must be followed by space after: key: iex(2)> map = %{key: 0} %{key: 0}

2.全部的key必須是原子類型才能這麼用.

正則表達式

Elixir支持正則表達式的字面語法. 這樣的語法容許正則表達式在編譯時被編譯而不是運行時進行編譯, 而且不要求轉義特殊的正則表達式符號:

Erlang

{ ok, Pattern } = re:compile("abc\\s"). re:run("abc ", Pattern). %=> { match, ["abc "] }

Elixir:

Regex.run ~r/abc\s/, "abc " #=> ["abc "]

正則表達式還能用在heredocs當中, 提供了一個定義多行正則表達式的便捷的方法:

Regex.regex? ~r""" This is a regex spanning several lines. """

模塊

每一個erlang模塊保存在其本身的文件中, 而且有以下結構:

-module(hello_module). -export([some_fun/0, some_fun/1]). % A "Hello world" function some_fun() -> io:format('~s~n', ['Hello world!']). % This one works only with lists some_fun(List) when is_list(List) -> io:format('~s~n', List). % Non-exported functions are private priv() -> secret_info.

這裏咱們建立一個名爲hello_module的模塊. 其中咱們定義了三個函數, 前兩個用於其餘模塊調用, 並經過export指令導出. 它包含一個要導出的函數列表, 其中沒個函數的書寫格式爲<function name>/<arity>arity標書參數的個數.

上面的Elixir等效代碼爲:

defmodule HelloModule do # A "Hello world" function def some_fun do IO.puts "Hello world!" end # This one works only with lists def some_fun(list) when is_list(list) do IO.inspect list end # A private function defp priv do :secret_info end end

在Elixir中, 還能夠在一個文件中定義多個模塊, 以及嵌套模塊.

defmodule HelloModule do defmodule Utils do def util do IO.puts "Utilize" end defp priv do :cant_touch_this end end def dummy do :ok end end defmodule ByeModule do end HelloModule.dummy #=> :ok HelloModule.Utils.util #=> "Utilize" HelloModule.Utils.priv #=> ** (UndefinedFunctionError) undefined function: HelloModule.Utils.priv/0

函數語法

Erlang 圖書的這章提供了模式匹配和函數語法的詳細描述. 這裏我簡單的覆蓋一些要點並提供Erlang和Elixir的代碼示例:

模式匹配

Erlang

loop_through([H|T]) -> io:format('~p~n', [H]), loop_through(T); loop_through([]) -> ok.

Elixir

def loop_through([h|t]) do IO.inspect h loop_through t end def loop_through([]) do :ok end

當定義一個同名函數屢次的時候, 沒個這樣的定義稱爲分句. 在Erlang中, 分句老是緊挨着的, 而且由分號;分割. 最後一個分句經過點.終止.

Elixir並不要求使用標點符號來分割分句, 可是他們必須分組在一塊兒(同名函數必須上下緊接着)

標識函數

在Erlang和Elixir中, 函數不單單由名字來標識, 而是由名字參數的個數共同來標識一個函數. 在下面兩個例子中, 咱們定義了四個不一樣的函數(所有名爲sum, 不一樣的參數個數)

Erlang

sum() -> 0. sum(A) -> A. sum(A, B) -> A + B. sum(A, B, C) -> A + B + C.

Elixir

def sum, do: 0 def sum(a), do: a def sum(a, b), do: a + b def sum(a, b, c), do: a + b + c

基於某些條件, Guard表達式(Guard expressions), 提供了一個精確的方式定義接受特定取值的函數

Erlang

sum(A, B) when is_integer(A), is_integer(B) -> A + B; sum(A, B) when is_list(A), is_list(B) -> A ++ B; sum(A, B) when is_binary(A), is_binary(B) -> <<A/binary, B/binary>>. sum(1, 2). %=> 3 sum([1], [2]). %=> [1,2] sum("a", "b"). %=> "ab"

Elixir

def sum(a, b) when is_integer(a) and is_integer(b) do a + b end def sum(a, b) when is_list(a) and is_list(b) do a ++ b end def sum(a, b) when is_binary(a) and is_binary(b) do a <> b end sum 1, 2 #=> 3 sum [1], [2] #=> [1,2] sum "a", "b" #=> "ab"

默認值

Erlang不支持默認值

Elixir 容許參數有默認值

def mul_by(x, n \\ 2) do x * n end mul_by 4, 3 #=> 12 mul_by 4 #=> 8

匿名函數

匿名函數以以下方式定義:

Erlang

Sum = fun(A, B) -> A + B end. Sum(4, 3). %=> 7 Square = fun(X) -> X * X end. lists:map(Square, [1, 2, 3, 4]). %=> [1, 4, 9, 16]

當定義匿名函數的時候也能夠使用模式匹配.

Erlang

F = fun(Tuple = {a, b}) -> io:format("All your ~p are belong to us~n", [Tuple]); ([]) -> "Empty" end. F([]). %=> "Empty" F({a, b}). %=> "All your {a,b} are belong to us"

Elixir

f = fn {:a, :b} = tuple -> IO.puts "All your #{inspect tuple} are belong to us" [] -> "Empty" end f.([]) #=> "Empty" f.({:a, :b}) #=> "All your {:a, :b} are belong to us"

一類函數

匿名函數是第一類值, 他們能夠做爲參數傳遞給其餘函數, 也能夠做爲返回值. 這裏有一個特殊的語法容許命名函數以相同的方式對待:

Erlang

-module(math). -export([square/1]). square(X) -> X * X. lists:map(fun math:square/1, [1, 2, 3]). %=> [1, 4, 9]

Elixir

defmodule Math do def square(x) do x * x end end Enum.map [1, 2, 3], &Math.square/1 #=> [1, 4, 9]

Partials in Elixir

Elixir supports partial application of functions which can be used to define anonymous functions in a concise way:

Enum.map [1, 2, 3, 4], &(&1 * 2) #=> [2, 4, 6, 8] List.foldl [1, 2, 3, 4], 0, &(&1 + &2) #=> 10

Partials also allow us to pass named functions as arguments.

defmodule Math do def square(x) do x * x end end Enum.map [1, 2, 3], &Math.square/1 #=> [1, 4, 9]

控制流

The constructs if and case are actually expressions in both Erlang and Elixir, but may be used for control flow as in imperative languages.

Case

The case construct provides control flow based purely on pattern matching.

Erlang

case {X, Y} of {a, b} -> ok; {b, c} -> good; Else -> Else end

Elixir

case {x, y} do {:a, :b} -> :ok {:b, :c} -> :good other -> other end

If

Erlang

Test_fun = fun (X) -> if X > 10 -> greater_than_ten; X < 10, X > 0 -> less_than_ten_positive; X < 0; X =:= 0 -> zero_or_negative; true -> exactly_ten end end. Test_fun(11). %=> greater_than_ten Test_fun(-2). %=> zero_or_negative Test_fun(10). %=> exactly_ten

Elixir

test_fun = fn(x) -> cond do x > 10 -> :greater_than_ten x < 10 and x > 0 -> :less_than_ten_positive x < 0 or x === 0 -> :zero_or_negative true -> :exactly_ten end end test_fun.(44) #=> :greater_than_ten test_fun.(0) #=> :zero_or_negative test_fun.(10) #=> :exactly_ten

區別:

  1. cond容許左側爲任意表達式, erlang只容許guard子句.

  2. cond中的條件只有在表達式爲nilfalse的時候爲false, 其餘狀況一概爲true, Erlang爲一個嚴格的布爾值

Elixr還提供了一個簡單的if結構

if x > 10 do :greater_than_ten else :not_greater_than_ten end

發送和接受消息

Erlang

Pid = self().

Pid ! {hello}.

receive {hello} -> ok; Other -> Other after 10 -> timeout end.

Elixir

pid = Kernel.self send pid, {:hello} receive do {:hello} -> :ok other -> other after 10 -> :timeout end

添加Elixir到現有的Erlang程序

Rebar集成

若是使用Rebar,能夠把Elixir倉庫做爲依賴.

https://github.com/elixir-lang/elixir.git

Elixir其實是一個Erlang的app. 它被放在lib目錄中, rebar不知道這樣的目錄結構. 所以須要制定Elixir的庫目錄.

 
轉自:https://segmentfault.com/a/1190000004882064{lib_dirs, [
  "deps/elixir/lib" ]}.
相關文章
相關標籤/搜索