module
module 是程式碼的容器,每個 module 的名字都是 global 唯一的 atom。
呼叫函數
local 呼叫是指呼叫同一個 module 裡的函數
remote 呼叫是指呼叫其他 module 裡的函數
以 module:fun 的方式呼叫函數
erlang 的函數數量稱為 arity 元數,函數的全名必須要包含 arity,例如 reverse/1、lists:reverse/1、lists:reverse/2
18> lists:reverse([3,2,1]).
[1,2,3]
19> lists:reverse([5,6,7],[3,2,1]).
[7,6,5,3,2,1]
BIF: built-in function
erlang 內建一套標準函式庫,散布在各個 module 中,例如: erlang、lists、dict、array。
BIF 會自動被 include,不需要 include_lib,例如 self() 其實就是 erlang:self(),因為自動引用,所以可以省略 erlang:
自建 module
建立 test_module.erl 檔案
%% test_module.erl
-module(test_module).
-export[hello/0].
-export[hello/1].
hello(From) ->
io:format( "~s:Hello world~n", [From] ).
hello() ->
hello("").
可在 linux shell 裡面直接以 erlc 編譯,會產生 test_module.beam 檔案,可使用 -o 指定 .beam 輸出的目錄。
> erlc test_module.erl
> erlc -o ebin test_module.erl
在 erl shell 裡面,erlang 會直接嘗試載入 test_module,但如果有修改 test_module.erl,也可以直接以 c(test_module) 編譯並載入更新後的 test_module
1> test_module:hello().
Hello world
ok
2> test_module:hello("test").
test:Hello world
ok
3> c(test_module).
{ok,test_module}
4> test_module:hello("test").
test:Hello world
ok
5> test_module:hello().
:Hello world
ok
code:get_path(). 可將所有 shell 會自動搜尋的路徑列印出來
4> code:get_path().
[".","/usr/local/lib/erlang/lib/kernel-2.16.4/ebin",
"/usr/local/lib/erlang/lib/stdlib-1.19.4/ebin",
"/usr/local/lib/erlang/lib/xmerl-1.3.5/ebin",
"/usr/local/lib/erlang/lib/wx-1.1.1/ebin",
"/usr/local/lib/erlang/lib/webtool-0.8.9.2/ebin",
"/usr/local/lib/erlang/lib/typer-0.9.5/ebin",
"/usr/local/lib/erlang/lib/tv-2.1.4.10/ebin",
"/usr/local/lib/erlang/lib/tools-2.6.13/ebin",
"/usr/local/lib/erlang/lib/toolbar-1.4.2.3/ebin",
"/usr/local/lib/erlang/lib/test_server-3.6.4/ebin",
"/usr/local/lib/erlang/lib/syntax_tools-1.6.12/ebin",
"/usr/local/lib/erlang/lib/ssl-5.3.2/ebin",
"/usr/local/lib/erlang/lib/ssh-3.0/ebin",
"/usr/local/lib/erlang/lib/snmp-4.25/ebin",
"/usr/local/lib/erlang/lib/sasl-2.3.4/ebin",
"/usr/local/lib/erlang/lib/runtime_tools-1.8.13/ebin",
"/usr/local/lib/erlang/lib/reltool-0.6.4.1/ebin",
"/usr/local/lib/erlang/lib/public_key-0.21/ebin",
"/usr/local/lib/erlang/lib/pman-2.7.1.4/ebin",
"/usr/local/lib/erlang/lib/percept-0.8.8.2/ebin",
"/usr/local/lib/erlang/lib/parsetools-2.0.10/ebin",
"/usr/local/lib/erlang/lib/otp_mibs-1.0.8/ebin",
"/usr/local/lib/erlang/lib/os_mon-2.2.14/ebin",
"/usr/local/lib/erlang/lib/orber-3.6.26.1/ebin",
"/usr/local/lib/erlang/lib/odbc-2.10.18/ebin",
"/usr/local/lib/erlang/lib/observer-1.3.1.2/ebin",
"/usr/local/lib/erlang/lib/mnesia-4.11/ebin",
[...]|...]
variable
erlang 的變數必須以大寫的字母開頭,變數中每個單字的開頭,都要大寫(CamelCase)。
變數也可以用 _ 底線開頭,但以底線開頭的變數,就不會觸發沒有使用到這個變數的編譯器的警告,所有未被使用的變數,都會被優化掉。
Name
ShoeSize
ThisIsAVariable
_Name
_ShoeSize
底線變數有兩個用途
- 為我們不想用到的變數命名,例如寫 open(File, Mode) 比寫 open(File, ),程式更具有可讀性。
- 為了除錯的目的
如果將io:format 改為註解,編譯時,就會發生 Q 沒有使用的警告some_func(X) -> {P,Q} = some_other_func(X), io:format("Q= ~p~n", [Q]), P.
因此我們把 Q 改為 _Q,就可以避免產生警告訊息some_func(X) -> {P,Q} = some_other_func(X), %% io:format("Q= ~p~n", [Q]), P.
some_func(X) -> {P,_Q} = some_other_func(X), io:format("_Q= ~p~n", [_Q]), P.
single assignment
當變數被指定數值時,該變數在程式作用的範圍中,就不會變動。
在 shell 中,只要這個 shell 還在運作,變數就不能異動,一旦異動,就會收到 pattern matching 的錯誤。但可以使用 f() 把變數的 binding 值忘記,然後就可以再次指定新值。
6> _Name=2.
2
7> _Name=3.
** exception error: no match of right hand side value 3
8> f(_Name).
ok
9> _Name=3.
3
pattern matching
這是 erlang 最重要的功能,pattern matching 是加強版的 value binding,有以下的用途:
- 選擇程式控制分支
- 完成變數binding
- 拆解資料結構
= 就是 pattern matching 的運算符號
11> {A,B,C}={2014,"NewYear",ok}.
{2014,"NewYear",ok}
12> A.
2014
13> C.
ok
14> B.
"NewYear"
15> {rect, Width, Height} = {rect, 100, 20}.
{rect,100,20}
16> Width.
100
{rect, Width, Height} 利用 rect 這個 atom 作為 tuple 資料的標籤,可在 pattern matching 時,馬上確認並檢查此資料來源的正確性。
don't care pattern: _
當我們有個 Users 的資料結構,裡面存有兩個 users,在這樣複雜的結構下,我們要怎麼確認第一個人符合我們設定條件呢?
用以下的方式,可確認第一個人 LastName 是不是 "Chen",同時取得那個人的 Firname 與 Age。
25> Users = [{person, [{name, "John", "Chen"}, {age, 30}, {tags, [math, male]}]}, {person, [{name, "James", "Chen"}, {age, 33}, {tags, [cs, female]}]} ].
[{person,[{name,"John","Chen"},{age,30},{tags,[math,male]}]},
{person,[{name,"James","Chen"},
{age,33},
{tags,[cs,female]}]}]
26> [{person, [{name, Firstname, "Chen"}, {age, Age}, {tags, _}]} | _ ] = Users.
[{person,[{name,"John","Chen"},
{age,30},
{tags,[math,male]}]}]
27> Firstname.
"John"
28> Age.
30
可將 Rest 直接 bind 到後面三個元素的list。
6> [1,2,3 | Rest] = [1,2,3,4,5,6].
[1,2,3,4,5,6]
7> Rest.
[4,5,6]
可以套用在 strings 上,因為 string 也是一種 list。也可以直接使用 ++ 並進行 pattern matching。
8> [$h, $t, $t, $p, $: | Url]="http://www.maxkit.com.tw".
"http://www.maxkit.com.tw"
9> Url.
"//www.maxkit.com.tw"
12> "http://" ++ Rest1 = "http://www.maxkit.com.tw".
"http://www.maxkit.com.tw"
13> Rest1.
"www.maxkit.com.tw"
參考
Erlang and OTP in Action
Programming Erlang: Software for a Concurrent World
沒有留言:
張貼留言