Erlang 入門 ---- 基礎(一)


Erlang 入門

基礎

安裝 Erlang Shell

For Homebrew on OS X: brew install erlang
For MacPorts on OS X: port install erlang
For Ubuntu and Debian: apt-get install erlang
For Fedora: yum install erlang
For FreeBSD: pkg install erlang

基本使用

啟動與退出

在終端中輸入 erl 即可進入 Erlang Shell

% 這是一個單行注釋,Erlang 中沒有多行注釋
% Erlang 中 . 表示語句的結束 (類似 Java/C 語言中的 分號)
% Erlang Shell 類似 Python 的 IDLE,可以直接進行運算
% Erlang 為函數式語言,所有函數、表達式都有返回值,運行成功時都會返回一個 atom 類型的 ok
io:format("hello world!~n"). % 打印 hello world,~n 表示換行
1 + 1. % 輸出 2
q(). % init():stop(). 的快捷方式,退出 Erlang Shell

變量

Erlang動態類型(聲明變量時候不需要指定類型)同時也是強類型(Erlang 不會自動的進行類型轉換)的語言

% pattern match (模式匹配)
A = 1. % 在 Erlang 中 = 稱為模式匹配,后面會再講
% 若 A 沒有值,則會將右邊的值綁定到 A,相當於賦值
% 若 A 有值且兩邊值相等,則匹配成功,否則報錯
% 變量只有綁定才可以使用,雖然稱之為變量,但實際是 'Immutable' (不可變的)
_Age = 2. % 下划線開頭的變量,即使沒有使用/綁定也沒關系,編譯也不會報錯

函數

Add = fun(A, B) -> A + B end. % 聲明一個匿名函數,需要兩個參數,綁定到 Add 變量上
Add(1,2). % 調用

基本類型

Number

1 + 1. % 2
1 * 2. % 2
2 - 1. % 1
5 / 2. % 2.5
5 div 2. % 2, div 表示整除
5 rem 2. % 1 rem 表示取余

% 不同進制表示,格式:Base#Value,Base 默認為 10
2#10. % 表示二進制的 10,即十進制的 2
8#10. % 表示8進制的 10, 即十進制的 8
...

Atoms

可以理解為一個常量,atom 類型使用內存很小且運算速度很快,但注意數量是有限制的。

% 以下都是合法的 atom 類型
atom.
atom_rule.
atom_@123.
'Atom 123'. % 包含特殊字符需要寫在單引號中
atom = 'atom'.
% true、false 就是一種 atom 類型

Tuples

元組是不用類型的值組成的一個類型。語法:{element1, element2, ..., elementN}

{1,2}.
% 一般情況下,會使用 atom 類型作為第一個值用於標注這個元組的含義,稱之為 'tagged tuple'
{point, 1, 2}. % 表示一個點坐標
{rectangle, 2, 3}. % 表示一個矩形的長度和寬度

List

List就是鏈表,可以包含各種類型的值

% 常用語法
[1, 2, 3].
[1, [2,3], {4}].

% Erlang 中 String 就是 List
"abc"
[97, 98, 99]. % 與上一行等效

% 操作符
[1, 2] -- [1]. % [2]
[1] ++ [2]. % [1, 2]

List = [1,2]
hd(List). % 1
tl(List). % 2
[0 | List]. % [0, 1, 2],頭部插入一個 0

% List Comprehensions 語法, 可以根據需求生產新的 List
[2*N || N <- [1,2]]. % [2, 4], 將列表元素乘 2
[N || N <- [1,2], N rem 2 =:= 0]. % [2],取出列表中的偶數
Tips:
  • 列表相對來說拼接等操作比較耗時,同時比較占內存,字符串可以使用內存更小的 Binary 類型,比如:<<"abc">>
  • TupleList 最大的區別在於定長不定長(個人理解)

運算符

邏輯運算符
true and false. % false,與 andalso 類似
true or false. % true, 與 orelse 類似
true xor false. % true
not false. % true
% and/or 和 andalso/orelse 區別在於后者右邊的運算不一定會執行
比較運算符
1 < 2. % true
2 > 1. % true
1 =< 2. % true % 注意寫法 =<
1 >= 2. % false

1 =:= 1. % true,嚴格相等
1 == 1.0. % true,大概相等
1 =/= 1. % false,嚴格不等
1 /= 2. % true,相差很多
% =:= 為判斷相等,=/=判斷不等(包括類型)

不同類型之間也存在大小關系:number < atom < reference < fun < port < pid < tuple < list < bit string

Modules

定義與使用

% test.erl
-modules(test). % 定義模塊,需要與文件名一致
-export([add/2, add/3]). % 指定導出的函數,未導出函數無法調用
% [function/paramNum], 存在同名函數但是參數個數不一樣格式如上一行
add(A, B) -> A + B.
add(A, B, C) -> A + add(B + C).

當存在參數個數相同的函數用 分號 隔開

% test2.erl
-module(test2).
-export([add/2]).

% 當 A 和 B 都是數字時
add(A, B) when is_number(A), is_number(B) ->
  A + B; % 此處分號隔開

% 當 A 和 B 都是列表時
add(A, B) when is_list(A), is_list(B) ->
  A ++ B.

% 調用時會從上往下匹配,其余情況沒有匹配不執行

單個文件的編譯與運行

方法一

cmd 中編譯 erlang 文件

:: 這是 cmd 中的注釋,測試環境為 windows
mkdir ebin :: 創建一個文件夾 ebin
erlc -o ebin test.erl :: 編譯 test.erl,將編譯后文件放到 ebin 文件夾中
erl -pa ebin :: 將 ebin 文件夾加入 erlang beam 文件查找目錄並啟動 erlang shell

erlang shell 中調用函數

% 只有按照上面的操作后以下方法才會生效
test:add(1, 2). % 3
test:add(1, 2, 3). % 6
方法二
% 在 erl 文件所在的地方打開 cmd, `erl` 進入 erlang shell
c(test). % 編譯后原地生成 beam 文件
test:add(1, 2). % 3
test:add(1, 2, 3). % 6

模式匹配

case clauses

類似其他語言中的 switch case 語句,通過匹配不同的條件選擇不同分支

% test.erl
-modules(test). 
-export([show/1]).
% 示例函數
show(Color) -> 
    case Color of
        red -> io:fomat("So hot.");
        blue -> io:fomat("So cool.");
        _ -> io:fomat("So ...") % _ 是一個特殊的變量,單獨使用可以匹配任何東西
    end.

function clauses

% test.erl
-modules(test). 
-export([show/1]).
% 示例函數
show(red) -> io:fomat("So hot.");
show(blue) -> io:fomat("So cool");
show(_) -> io:fomat("So ...").

匹配獲取值

{X | 2} = {1, 2}. % X = 1
[X | Y] = [1, 2, 3] % X = 1, Y = [2,3]
[_ | X] = [1, 2] % X = 2
f(). % 解綁所有變量

When

% 18 歲才可以...
fun(X) when X >= 18 -> true;
fun(_) -> false.
% 14-18歲之間...
fun(X) when X <= 18, X >=14 -> true;
fun(_) -> false.

when 中 , 表示 and ; 表示 or,可以使用 andalsoorels

Records

tagged tuple 類似,但是更加直觀

% records.erl
-module(records).
-export([get_user_name/1,
         get_user_phone/1]).

-record(user, {
  name,
  phone
}).

get_user_name(#user{name=Name}) ->
  Name.

get_user_phone(#user{phone=Phone}) ->
  Phone.
% 進入 erlang shell
c(records). % 編譯文件
rr(records). % 將 record 加載到 shell 中
User = #user{name=<<"Jeson">>, phone=<<"123">>}. % 定義一個 record
Name = record:get_user_name(User). % Jeson,獲取 User 中的名字
Phone = record:get_user_phone(User). % 123

User#user.name. % Jeson
#user.name. % 2,record 本質就是一個 tagged tuple,所有 name 是第二個元素

Erlang 中位置從 1 開始計算

遞歸

因為 Erlang沒有迭代語句,所以使用遞歸解決大部分的問題

% 場景:計算一個 List 的長度

len([]) -> 0;
len([_|T]) -> 1 + len(T). % 遞歸計算長度

尾遞歸

上述遞歸存在一個問題,就是需要遞歸到最深處再回溯進行相加操作,對內存消耗較大,可以使用尾遞歸進行優化

len(T) -> len(T, 0). %調用尾遞歸函數

len([], Len) -> Len;
len([_|T], Len) -> len(T, Len+1).

制作一個簡單的 GIF 演示一下:

並行

參考資料:簡書


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM