language: erlang
lang: zh-cn
contributors:html
- ["Giovanni Cappellotto", "http://www.focustheweb.com/"]
translators:node
- ["Jakukyo Friel", "http://weakish.github.io"]
% 百分比符號標明註釋的開始。git
%% 兩個符號一般用於註釋函數。github
%%% 三個符號一般用於註釋模塊。web
% Erlang 裏使用三種標點符號:
% 逗號 (,
) 分隔函數調用中的參數、數據構建和模式。
% 句號 (.
) (後跟空格)分隔函數和 shell 中的表達式。
% 分號 (;
) 分隔語句。如下環境中使用語句:
% 函數定義和case
、if
、try..catch
、receive
表達式。shell
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%編程
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%數組
Num = 42. % 變量必須以大寫字母開頭。 % Erlang 的變量只能賦值一次。若是給變量賦不一樣的值,會致使錯誤: Num = 43. % ** exception error: no match of right hand side value 43 % 大多數語言中`=`表示賦值語句,在Erlang中,則表示模式匹配。 % `Lhs = Rhs`實際上意味着: % 演算右邊(Rhs), 將結果與左邊的模式匹配。 Num = 7 * 6. % 浮點數 Pi = 3.14159. % Atoms 用於表示非數字的常量。 % Atom 以小寫字母開始,包含字母、數字、`_`和`@`。 Hello = hello. OtherNode = example@node. % Atom 中若是包含特殊字符,能夠用單引號括起。 AtomWithSpace = 'some atom with space'. % Erlang 的元組相似 C 的 struct. Point = {point, 10, 45}. % 使用模式匹配操做符`=`獲取元組的值。 {point, X, Y} = Point. % X = 10, Y = 45 % 咱們可使用`_`存放咱們不感興趣的變量。 % `_`被稱爲匿名變量。和其餘變量不一樣, % 同一個模式中的多個`_`變量沒必要綁定到相同的值。 Person = {person, {name, {first, joe}, {last, armstrong}}, {footsize, 42}}. {_, {_, {_, Who}, _}, _} = Person. % Who = joe % 列表使用方括號,元素間使用逗號分隔。 % 列表的元素能夠是任意類型。 % 列表的第一個元素稱爲列表的 head,其他元素稱爲列表的 tail。 ThingsToBuy = [{apples, 10}, {pears, 6}, {milk, 3}]. % 若`T`是一個列表,那麼`[H|T]`一樣是一個列表,head爲`H`,tail爲`T`. % `|`分隔列表的 head 和 tail. % `[]`是空列表。 % 咱們可使用模式匹配操做來抽取列表中的元素。 % 若是咱們有一個非空的列表`L`,那麼`[X|Y] = L`則 % 抽取 L 的 head 至 X,tail 至 Y (X、Y需爲未定義的變量)。 [FirstThing|OtherThingsToBuy] = ThingsToBuy. % FirstThing = {apples, 10} % OtherThingsToBuy = {pears, 6}, {milk, 3} % Erlang 中的字符串實際上是由整數組成的數組。字符串使用雙引號。 Name = "Hello". [72, 101, 108, 108, 111] = "Hello".
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%併發
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%app
% Module 是 Erlang 代碼的基本單位。咱們編寫的全部函數都儲存在 module 中。 % Module 存儲在後綴爲 `.erl` 的文件中。 % Module 必須事先編譯。編譯好的 module 以 `.beam` 結尾。 -module(geometry). -export([area/1]). % module 對外暴露的函數列表 % `area`函數包含兩個分句,分句間以分號相隔。 % 最後一個分句以句號加換行結尾。 % 每一個分句由頭、體兩部門組成。 % 頭部包含函數名稱和用括號括起的模式, % 體部包含一系列表達式,若是頭部的模式和調用時的參數匹配,這些表達式會被演算。 % 模式匹配依照定義時的順序依次進行。 area({rectangle, Width, Ht}) -> Width * Ht; area({circle, R}) -> 3.14159 * R * R. % 編譯文件爲 geometry.erl. c(geometry). % {ok,geometry} % 調用函數時必須使用 module 名和函數名。 geometry:area({rectangle, 10, 5}). % 50 geometry:area({circle, 1.4}). % 6.15752 % 在 Erlang 中,同一模塊中,參數數目不一樣,名字相同的函數是徹底不一樣的函數。 -module(lib_misc). -export([sum/1]). % 對外暴露的`sum`函數接受一個參數:由整數組成的列表。 sum(L) -> sum(L, 0). sum([], N) -> N; sum([H|T], N) -> sum(T, H+N). % fun 是匿名函數。它們沒有名字,不過能夠賦值給變量。 Double = fun(X) -> 2*X end. % `Double` 指向匿名函數 #Fun<erl_eval.6.17052888> Double(2). % 4 % fun 能夠做爲函數的參數和返回值。 Mult = fun(Times) -> ( fun(X) -> X * Times end ) end. Triple = Mult(3). Triple(5). % 15 % 列表解析是建立列表的表達式(不使用fun、map 或 filter)。 % `[F(X) || X <- L]` 表示 "由 `F(X)` 組成的列表,其中 `X` 取自列表 `L`。 L = [1,2,3,4,5]. [2*X || X <- L]. % [2,4,6,8,10] % 列表解析可使用生成器,也可使用過濾器,過濾器用於篩選列表的一部分。 EvenNumbers = [N || N <- [1, 2, 3, 4], N rem 2 == 0]. % [2, 4] % Guard 是用於加強模式匹配的結構。 % Guard 可用於簡單的測試和比較。 % Guard 可用於函數定義的頭部,以`when`關鍵字開頭,或者其餘可使用表達式的地方。 max(X, Y) when X > Y -> X; max(X, Y) -> Y. % guard 能夠由一系列 guard 表達式組成,這些表達式以逗號分隔。 % `GuardExpr1, GuardExpr2, ..., GuardExprN` 爲真,當且僅當每一個 guard 表達式均爲真。 is_cat(A) when is_atom(A), A =:= cat -> true; is_cat(A) -> false. is_dog(A) when is_atom(A), A =:= dog -> true; is_dog(A) -> false. % guard 序列 `G1; G2; ...; Gn` 爲真,當且僅當其中任意一個 guard 表達式爲真。 is_pet(A) when is_dog(A); is_cat(A) -> true; is_pet(A) -> false. % Record 能夠將元組中的元素綁定到特定的名稱。 % Record 定義能夠包含在 Erlang 源代碼中,也能夠放在後綴爲`.hrl`的文件中(Erlang 源代碼中 include 這些文件)。 -record(todo, { status = reminder, % Default value who = joe, text }). % 在定義某個 record 以前,咱們須要在 shell 中導入 record 的定義。 % 咱們可使用 shell 函數`rr` (read records 的簡稱)。 rr("records.hrl"). % [todo] % 建立和更新 record。 X = #todo{}. % #todo{status = reminder, who = joe, text = undefined} X1 = #todo{status = urgent, text = "Fix errata in book"}. % #todo{status = urgent, who = joe, text = "Fix errata in book"} X2 = X1#todo{status = done}. % #todo{status = done,who = joe,text = "Fix errata in book"} % `case` 表達式。 % `filter` 返回由列表`L`中全部知足`P(x)`爲真的元素`X`組成的列表。 filter(P, [H|T]) -> case P(H) of true -> [H|filter(P, T)]; false -> filter(P, T) end; filter(P, []) -> []. filter(fun(X) -> X rem 2 == 0 end, [1, 2, 3, 4]). % [2, 4] % `if` 表達式。 max(X, Y) -> if X > Y -> X; X < Y -> Y; true -> nil; end. % 警告: `if` 表達式裏至少有一個 guard 爲真,不然會觸發異常。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 當遇到內部錯誤或顯式調用時,會觸發異常。 % 顯式調用包括 `throw(Exception)`, `exit(Exception)` 和 % `erlang:error(Exception)`. generate_exception(1) -> a; generate_exception(2) -> throw(a); generate_exception(3) -> exit(a); generate_exception(4) -> {'EXIT', a}; generate_exception(5) -> erlang:error(a). % Erlang 有兩種捕獲異常的方法。其一是將調用包裹在`try...catch`表達式中。 catcher(N) -> try generate_exception(N) of Val -> {N, normal, Val} catch throw:X -> {N, caught, thrown, X}; exit:X -> {N, caught, exited, X}; error:X -> {N, caught, error, X} end. % 另外一種方式是將調用包裹在`catch`表達式中。 % 此時異常會被轉化爲一個描述錯誤的元組。 catcher(N) -> catch generate_exception(N).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Erlang 依賴於 actor併發模型。在 Erlang 編寫併發程序的三要素: % 建立進程,發送消息,接收消息 % 啓動一個新的進程使用`spawn`函數,接收一個函數做爲參數 F = fun() -> 2 + 2 end. % #Fun<erl_eval.20.67289768> spawn(F). % <0.44.0> % `spawn` 函數返回一個pid(進程標識符),你可使用pid向進程發送消息。 % 使用 `!` 操做符發送消息。 % 咱們須要在進程內接收消息,要用到 `receive` 機制。 -module(caculateGeometry). -compile(export_all). caculateAera() -> receive {rectangle, W, H} -> W * H; {circle, R} -> 3.14 * R * R; _ -> io:format("We can only caculate area of rectangles or circles.") end. % 編譯這個模塊,在 shell 中建立一個進程,並執行 `caculateArea` 函數。 c(caculateGeometry). CaculateAera = spawn(caculateGeometry, caculateAera, []). CaculateAera ! {circle, 2}. % 12.56000000000000049738 % shell也是一個進程(process), 你可使用`self`獲取當前 pid self(). % <0.41.0>