在Erlang內(nèi)部只有兩種混合的數(shù)據(jù)類型:List和Tuple,而這兩種都不支持命名訪問,所以如果沒有額外的庫的話想創(chuàng)建像PHP、Ruby或Python中的關(guān)聯(lián)數(shù)組(Ruby中的Hash)是不可能的
在Ruby中我可以這樣做:
復(fù)制代碼 代碼如下:
server_opts = {:port => 8080, :ip => '127.0.0.1', :max_connections => 10}
在Erlang的語法級別不支持這種表達(dá)
為了避免這種限制,Erlang虛擬機(jī)提供了一個偽數(shù)據(jù)類型,稱為Record
Record支持命名訪問,后面我們會看到為什么我們稱之為“偽”數(shù)據(jù)類型
定義Record
Record更類似于C中的struct,而不是關(guān)聯(lián)數(shù)組,后者必須一開始就定義好內(nèi)容并且只能保持?jǐn)?shù)據(jù)
這里是一個服務(wù)器的連接選項的Record例子:
復(fù)制代碼 代碼如下:
-module(my_server).
-record(server_opts,
{port,
ip="127.0.0.1",
max_connections=10}).
% The rest of your code goes here.
Record使用-record指令來聲明,第一個參數(shù)是Record的名字,第二個參數(shù)是一個Tuple,Tuple包含了Record里的field和默認(rèn)值
在這里我們定義了server_opts這個Record,它有三個field:端口、IP和最大連接數(shù)
沒有默認(rèn)的port,ip默認(rèn)值為"127.0.0.1",max_connections默認(rèn)值為10
創(chuàng)建Record
Record通過使用#符號來創(chuàng)建,下面是創(chuàng)建server_opts這個Record的實例的合法方式:
復(fù)制代碼 代碼如下:
Opts1 = #server_opts{port=80}.
這段代碼創(chuàng)建了一個server_opts Record,port設(shè)置為80,其他field使用默認(rèn)值
Opts2 = #server_opts{port=80, ip="192.168.0.1"}.
這段代碼創(chuàng)建了一個server_opts Record,但是ip設(shè)置為"192.168.0.1"
簡而言之,當(dāng)創(chuàng)建一個Record時,你可以包含任何field,省略的field將使用默認(rèn)值
訪問Record
Record的訪問方式很笨拙,如果我想訪問port這個field,我可以這樣做:
復(fù)制代碼 代碼如下:
Opts = #server_opts{port=80, ip="192.168.0.1"},
Opts#server_opts.port
每次你想訪問一個Record時你都必須包含Record的名字,為什么要這樣?
因為Record不是真正的內(nèi)部數(shù)據(jù)類型,它只是編譯器的小把戲。
在內(nèi)部,Record是Tuple,如下:
復(fù)制代碼 代碼如下:
{server_opts, 80, "127.0.0.1", 10}
編譯器將Record的名字映射到Tuple里面
Erlang虛擬機(jī)記錄了Record的定義,而編譯器將所有的Record邏輯翻譯為Tuple邏輯
因此,根本就沒有Record類型,所以每次你訪問一個Record時你必須告訴Erlang我們在用哪個Record(為了編譯器爽,程序員變的很不爽)
更新Record
更新Record和創(chuàng)建Record很類似:
復(fù)制代碼 代碼如下:
Opts = #server_opts{port=80, ip="192.168.0.1"},
NewOpts = Opts#server_opts{port=7000}.
這里首先創(chuàng)建一個server_opts Record
NewOpts = Opts#{port=7000}創(chuàng)建了一個Opts的副本,并指定port為7000并綁定到NewOpts
匹配Record和Guard語句
不談模式匹配就不算Erlang
讓我們來看看一個例子:
復(fù)制代碼 代碼如下:
handle(Opts=#server_opts{port=8000}) ->
% do special port 8080 stuff
handle(Opts=#server_opts{} ->
% default stuff
Guard語句和上面的類似,例如綁定小于1024的端口通常需要root權(quán)限,所以我們可以這樣做:
復(fù)制代碼 代碼如下:
handle(Opts) when Opts#server_opts.port = 1024 ->
% requires root access
handle(Opts=#server_opts{}) ->
% Doesn't require root access
使用Record
在我使用Erlang的有限的時間里,我發(fā)現(xiàn)Record主要用在兩種場景
首先,Record用來保存狀態(tài),特別是在使用gen_server的behaviour時
由于Erlang不能全局保持狀態(tài),所以狀態(tài)必須在方法之前傳來傳去
然后,Record可以用來保存配置選項,這可以認(rèn)為是第一點(diǎn)的子集
盡管如此,Record也有一些限制,最明顯的是不能在運(yùn)行時添加和刪除field,這和C的struct一樣,Record的結(jié)構(gòu)必須預(yù)先定義
如果你想在運(yùn)行時添加和刪除field,或者你在運(yùn)行時才能確定有哪些field,這時你應(yīng)該使用dict而不是Record
您可能感興趣的文章:- Go/Python/Erlang編程語言對比分析及示例代碼
- python讀取excel表格生成erlang數(shù)據(jù)
- Erlang實現(xiàn)的一個Web服務(wù)器代碼實例
- Erlang初學(xué):Erlang的一些特點(diǎn)和個人理解總結(jié)
- CentOS 6.5源碼安裝Erlang教程
- ERLANG和PYTHON互通實現(xiàn)過程詳解