Erlang中的Record詳解

roc_guo發表於2022-04-17

在Erlang內部只有兩種混合的資料型別:List和Tuple,而這兩種都不支援命名訪問,所以如果沒有額外的庫的話想建立像PHP、Ruby或Python中的關聯陣列(Ruby中的Hash)是不可能的

在Ruby中我可以這樣做:
複製程式碼程式碼如下:

server_opts = {:port => 8080, :ip => '127.0.0.1', :max_connections => 10}

在Erlang的語法級別不支援這種表達

為了避免這種限制,Erlang虛擬機器提供了一個偽資料型別,稱為Record
Record支援命名訪問,後面我們會看到為什麼我們稱之為“偽”資料型別

定義Record

Record更類似於C中的struct,而不是關聯陣列,後者必須一開始就定義好內容並且只能保持資料
這裡是一個伺服器的連線選項的Record例子:
複製程式碼程式碼如下:

-module(my_server). 
 
-record(server_opts, 
  {port, 
  ip="127.0.0.1", 
  max_connections=10}). 
 
% The rest of your code goes here.

Record使用-record指令來宣告,第一個引數是Record的名字,第二個引數是一個Tuple,Tuple包含了Record裡的field和預設值
在這裡我們定義了server_opts這個Record,它有三個field:埠、IP和最大連線數
沒有預設的port,ip預設值為"127.0.0.1",max_connections預設值為10

建立Record

Record透過使用#符號來建立,下面是建立server_opts這個Record的例項的合法方式:
複製程式碼程式碼如下:

Opts1 = #server_opts{port=80}.

這段程式碼建立了一個server_opts Record,port設定為80,其他field使用預設值

Opts2 = #server_opts{port=80, ip="192.168.0.1"}.

這段程式碼建立了一個server_opts Record,但是ip設定為"192.168.0.1"

簡而言之,當建立一個Record時,你可以包含任何field,省略的field將使用預設值

訪問Record

Record的訪問方式很笨拙,如果我想訪問port這個field,我可以這樣做:
複製程式碼程式碼如下:

Opts = #server_opts{port=80, ip="192.168.0.1"}, 
Opts#server_opts.port

每次你想訪問一個Record時你都必須包含Record的名字,為什麼要這樣?
因為Record不是真正的內部資料型別,它只是編譯器的小把戲。
在內部,Record是Tuple,如下:
複製程式碼程式碼如下:

{server_opts, 80, "127.0.0.1", 10}

編譯器將Record的名字對映到Tuple裡面
Erlang虛擬機器記錄了Record的定義,而編譯器將所有的Record邏輯翻譯為Tuple邏輯
因此,根本就沒有Record型別,所以每次你訪問一個Record時你必須告訴Erlang我們在用哪個Record(為了編譯器爽,程式設計師變的很不爽)

更新Record

更新Record和建立Record很類似:
複製程式碼程式碼如下:

Opts = #server_opts{port=80, ip="192.168.0.1"}, 
NewOpts = Opts#server_opts{port=7000}.

這裡首先建立一個server_opts Record
NewOpts = Opts#{port=7000}建立了一個Opts的副本,並指定port為7000並繫結到NewOpts

匹配Record和Guard語句

不談模式匹配就不算Erlang
讓我們來看看一個例子:
複製程式碼程式碼如下:

handle(Opts=#server_opts{port=8000}) -> 
  % do special port 8080 stuff 
handle(Opts=#server_opts{} -> 
  % default stuff

Guard語句和上面的類似,例如繫結小於1024的埠通常需要root許可權,所以我們可以這樣做:
複製程式碼程式碼如下:

handle(Opts) when Opts#server_opts.port <= 1024 -> 
  % requires root access 
handle(Opts=#server_opts{}) -> 
  % Doesn't require root access

使用Record[/yiji[

在我使用Erlang的有限的時間裡,我發現Record主要用在兩種場景.首先,Record用來儲存狀態,特別是在使用gen_server的behaviour時,由於Erlang不能全域性保持狀態,所以狀態必須在方法之前傳來傳去。然後,Record可以用來儲存配置選項,這可以認為是第一點的子集。儘管如此,Record也有一些限制,最明顯的是不能在執行時新增和刪除field,這和C的struct一樣,Record的結構必須預先定義,如果你想在執行時新增和刪除field,或者你在執行時才能確定有哪些field,這時你應該使用dict而不是Record。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2887489/,如需轉載,請註明出處,否則將追究法律責任。

相關文章