最簡潔的Erlang基礎

0x00 說在前面

Erlang讀音/ˈɜːrlæŋ/。第一次見到的時候總感受怎麼讀都讀不對,後來在維基上看到Erlang標註了音標,才能準確的讀出來,並且也沒那麼怪異。由於工做纔有機會接觸這門語言,也所以只有三天的時間能夠看《Erlang程序設計》這本書。學習這門語言的時候帶着一個工做目標:把一個Erlang日誌收集分析統計的代碼轉換成Python的。而Erlang的風格是儘可能不寫註釋,儘可能在寫函數名和變量名的時候表達清楚代碼的含義。這樣一來學習Erlang就成了必要的,很慶幸,領導給了三天時間學習,三天時間基本也足夠了。除了這一片基礎語法的入門篇以外,後續還有一篇或者兩篇併發編程和分佈式編程的,畢竟這個纔是Erlang擅長的領域。話很少說,show me your articlehtml

<!--more-->python

0x01 配置開發環境

依賴工具:程序員

  • Erlang版本:18.3
  • IDE:IDEA

下載連接:shell

IDEA配置Erlang插件:編程

0x02 基礎知識

註釋

  • % 百分比符號標明註釋的開始。
  • %% 兩個符號一般用於註釋函數。
  • %%% 三個符號一般用於註釋模塊。

變量

全部的變量都必須以大寫字母開頭,變量只可一次賦值,賦值以後不可在變。 f()函數釋放shell綁定變量。segmentfault

浮點數

  • 浮點數必須含有小數點且小數點後必須有一位10進制數
  • 用/來除兩個整數時相除結果會自動轉換成浮點數
  • div取整,rem取餘

三種標點符號

  • 整個函數的定義結束時用一個句號「.」
  • 函數參數,數據構建,順序語句之間,用逗號「,」分隔
  • 函數定義、caseiftry..catchreceive表達式中的模式匹配時,用分號「;」分界

恆等

恆等測試符號 =:=以及不等測試符號 =/=數據結構

塊表達式

當程序中某處的語法要求只能使用單個表達式可是邏輯上又須要在此使用多個表達式時,就可使用begin...end快表達式併發

begin
  Expr1,
  ...
  ExprN
end

0x03 內置數據結構

元組及模式匹配(解構)

  • _ 表明丟棄的變量,和python相同
  • 匹配時模式匹配符=左右兩邊的元組的結構必須相同。
1> Point = {point, 20, 43}.
{point,20,43}
2> {point, x, y} = Point.
** exception error: no match of right hand side value {point,20,43}
3> {point, X, Y} = Point.
{point,20,43}
4> X.
20
5> Y.
43
6> Person = {person, {name, {first, joe}, {last, armstrong}}, {footsize, 42}}.
{person,{name,{first,joe},{last,armstrong}},{footsize,42}}
7> {_, {_, {_, Who}, {_, _}}, {_, Size}} = Person.
{person,{name,{first,joe},{last,armstrong}},{footsize,42}}
8> Who.
joe
9> Size.
42

列表

  • 列表元素能夠是不一樣的類型。
  • 列表頭:列表的第一個元素
  • 列表尾:列表除第一個元素剩下的部分
  • 豎線符號|app

    • 將列表的頭和尾分割開來
    • [E1, E2, E4, ... , |L]:使用|向列表L的起始處加入多個元素構形成新的列表
  • 列表連接操做符 ++ (中綴添加操做符)

列表操做演示代碼分佈式

1> L = [1+7, hello, 2-2, {cost, apple, 30-20}, 3]. 
[8,hello,0,{cost,apple,10},3]
2> L1 = [123, {oranges, 4} | L].
[123,{oranges,4},8,hello,0,{cost,apple,10},3]
3> [E1 | L2] = L1.
[123,{oranges,4},8,hello,0,{cost,apple,10},3]
4> E1.
123
5> L2.
[{oranges,4},8,hello,0,{cost,apple,10},3]
6> [E2, E3 | L3] = L2.
[{oranges,4},8,hello,0,{cost,apple,10},3]
7> E3.
8

列表表達式

形式:[F(X) || X <- L]

1> L = [1, 2, 3, 4, 5].
[1,2,3,4,5]
2> [2 * X || X <- L].
[2,4,6,8,10]
3> [X || {a, X} <- [{a, 1}, {b, 2}, {c, 3}, {a, 4}, hello, "wow"]].
[1,4]

字符串

Erlang的字符串是一個整數列表。整數列表的內容由每個字符對應的ascii碼構成

1> I = $s.
115
2> [I-32, $u, $r, $p, $r, $i, $s, $e].
"Surprise"
3> $r.                                
114
4> [I-32, $u, $r, $p, 114, $i, $s, $e].
"Surprise"

映射組(Map)

映射組是一個由多個Key-Vaule結構組成的符合數據類型,相似於Python的字典。具體使用以下

1> M1 = #{"name" => "alicdn", "percentage" => 80}.
#{"name" => "alicdn","percentage" => 80}
2> maps:get("name", M1).
"alicdn"
3> M2 = maps:update("percentage", 50, M1).
#{"name" => "alicdn","percentage" => 50}
4> map_size(M1).
2
5> #{"name" := X, "percentage" := Y} = M2.
#{"name" => "alicdn","percentage" => 50}
6> X.
"alicdn"
7> Y.
50

構造映射組和模式匹配時的符號不同,=>:=的區別。常見的put方法參見erlang maps庫的使用。

0x04 模塊

  • 一個模塊存放於一個.erl文件中(模塊名和文件名相同)
  • 編譯模塊的命令:c(模塊名)。編譯成功以後就會加載到當前shell中
  • 調用模塊中的函數:模塊名:函數名(參數)
  • 導入模塊中的函數:-import(lists, [map/2, sum/1]).
  • 導出模塊中的函數:

    • 導出指定函數-export([start/0, area/2]).
    • 導出所有函數-compile(export_all).,避免在開發階段常常會向export中添加函數或者刪除函數
-module(learn_test).
-author("ChenLiang").

%% API
-export([area/1]).


area({rectangle, Width, Height}) -> Width * Height;
area({circle, R}) -> 3.14159 * R * R;
area({square, X}) -> X * X.

編譯模塊,調用函數

1> c(learn_test).
{ok,learn_test}
2> learn_test:area({circle, 2.0}).
12.56636
3>

0x05 函數

基本函數

同名同目(參數數量,arity)的纔是同一個函數。所以函數名相同,目不相同的函數是徹底不一樣的兩個函數。同名不一樣目的函數一般做爲輔助函數。

  • 函數不會顯示地返回值,函數中最後一條語句的執行結果將做爲函數的返回值。
  • 同一個函數中,並列的邏輯分支之間,用分號 「;」 分界;順序語句之間,用逗號 「,」 分隔。

示例代碼:計算列表元素的和

-module(learn_test).
-author("ChenLiang").

%% API
-export([sum/1]).

sum(L) -> sum(L, 0).

sum([], N) -> N;
sum([H|T], N) -> sum(T, H + N).

匿名函數

erlang中的匿名函數就是fun。fun也能夠有若干個不一樣的字句。

1> Z = fun(X) -> 2*X end.
#Fun<erl_eval.6.50752066>
2> Double = Z.
#Fun<erl_eval.6.50752066>
3> Double(4).
8
4> TempConvert = fun({c, C}) -> {f, 32 + C * 9 / 5};
5> ({f, F}) -> {c, (F - 32) * 5 / 9}                
6> end.                                             
#Fun<erl_eval.6.50752066>
7> TempConvert({c, 100}).                           
{f,212.0}
8> TempConvert({f, 212}).
{c,100.0}

高階函數

返回fun或者接受fun做爲參數的函數都稱爲高階函數。

以fun爲參數的函數

常見的是lists模塊中的map(Fun, List1) -> List2,filter(Pred, List1) -> List2函數。

lists模塊的具體使用參見:https://www.erlang.org/doc/ma...

1> Even = fun(X) -> X rem 2 =:= 0 end.
#Fun<erl_eval.6.50752066>
2> lists:map(Even, [1, 2, 3, 4, 5, 6]).
[false,true,false,true,false,true]
3> lists:filter(Even, [1, 2, 3, 4, 5, 6]).
[2,4,6]

返回fun的函數

通常在返回的函數內部封裝了一些變量和邏輯。一般狀況下不寫返回fun的函數。

1> Mult = fun(Times) -> (fun(X) -> X * Times end ) end.
#Fun<erl_eval.6.50752066>
2> Triple = Mult(3).
#Fun<erl_eval.6.50752066>
3> Triple(4).
12

0x06 斷言

強化模式匹配的功能,給模式匹配增長一些變量測試和比較的能力

max(X, Y) when X > Y -> X;
max(_, Y) -> Y.

0x07 記錄

記錄是Erlang中基於元組的key-value數據定義,使用示例以下:

-module(learn_test).
-author("ChenLiang").

%% API
-export([record_test1/0, record_test2/0]).

-record(person, {name, age=18, hobby=["erlang"]}).    %% record定義能夠存放於hrl和erl中

record_test1() ->
  Person = #person{name="hahaha"},    %% 爲record中字段賦值
  Person#person.hobby.    %%  經過.操做符訪問record中字段

record_test2() ->
  Person = #person{},
  #person{name = Name} = Person,    %% 經過模式匹配獲取record字段
  Name. %% 輸出undefined

0x08 .hrl頭文件

某些文件的擴展名爲 .hrl。這些.hrl是在 .erl 文件中會用到的頭文件,使用方法以下:

-include("File_Name").

例如:

-include("mess_interface.hrl").

.hrl 文件中能夠包含任何合法的 Erlang 代碼,可是一般裏面只包含一些記錄和宏的定義。

0x09 case / if 表達式

case 表達式

case語句語法

case Experssion of
  Pattern1 [when Guard1] -> Expr_seq1;
  Pattern2 [when Guard2] -> Expr_seq2;
  ...
end

將Expression的結果和各個Pattern逐個匹配,匹配成功,則計算表達式序列的值,並返回。所有匹配不到,則直接報錯。

case語句使用示例:

-module(learn_test).
-author("ChenLiang").

%% API
-export([filter/2]).


filter(P, [H|T]) ->
  case P(H) of
    true -> [H|filter(P, T)];
    false -> filter(P, T)
  end
;
filter(_, []) -> [].

在erl shell中運行結果以下:

1> c(learn_test).
{ok,learn_test}
2> learn_test:filter(fun(X) -> X rem 2 =:= 0 end, [1, 2, 3, 4, 5]).
[2,4]

if 表達式

if語句使用示例

-module(learn_test).
-author("ChenLiang").

%% API
-export([bigger/2]).


bigger(X, Y) ->
  if
    X > Y -> X;
    X < Y -> Y;
    true -> -1
  end.

若是沒有匹配的斷言,則會拋出異常。所以最後一個斷言一般是true斷言。

0x10 異常

Erlang中一切都是表達式,都有返回值,所以異常捕獲語句也有返回值。

捕獲全部的異常_:_

-module(learn_test).
-author("ChenLiang").

%% API
-export([catch_exc1/0,catch_exc2/0]).


exception() ->
  exit({system, "123123"}).

catch_exc1() ->
  try
      exception()
  catch
      _:_  -> 111
  end.

catch_exc2() ->
  try
    exception()
  catch
    _  -> 222
  end.

erl shell輸出結果

1> learn_test:catch_exc1().
111
2> learn_test:catch_exc2().
** exception exit: {system,"123123"}
     in function  learn_test:exception/0 (learn_test.erl, line 17)
     in call from learn_test:catch_exc2/0 (learn_test.erl, line 28)

多種錯誤的檢測能夠 使用try catch風格。

參考stackoverflow-How do I elegantly check many conditions in Erlang?


記得幫我點贊哦!

精心整理了計算機各個方向的從入門、進階、實戰的視頻課程和電子書,按照目錄合理分類,總能找到你須要的學習資料,還在等什麼?快去關注下載吧!!!

resource-introduce

念念不忘,必有迴響,小夥伴們幫我點個贊吧,很是感謝。

我是職場亮哥,YY高級軟件工程師、四年工做經驗,拒絕鹹魚爭當龍頭的斜槓程序員。

聽我說,進步多,程序人生一把梭

若是有幸能幫到你,請幫我點個【贊】,給個關注,若是能順帶評論給個鼓勵,將不勝感激。

職場亮哥文章列表:更多文章

wechat-platform-guide-attention

本人全部文章、回答都與版權保護平臺有合做,著做權歸職場亮哥全部,未經受權,轉載必究!

相關文章
相關標籤/搜索