天天看點

Erlang_ets冷門函數fun2ms

最近接觸到一個函數叫ets:fun2ms/1,因為不了解被坑了,來解析下他的用法和常用情景

基本含義

把文法函數轉為比對規範的僞函數,聽到這個可能就蒙了,有啥用啊

使用一個解析轉換的仿函數 ListeralFun 作為參數傳遞給該函數轉換出一個比對規範。“literal” 意味着函數必須以的文本的形式作為函數的參數,它不能是依次傳遞給函數的變量。

需要注意的是,使用這個fun2ms的函數必須在代碼檔案前面加入這一行,

否則會報這個錯,我當時就找了半天bug

Erlang_ets冷門函數fun2ms

加了的話就會編譯正常

示例

2> ets:fun2ms(fun({M, N}) when N > 3 -> M end).
[{{'$1','$2'},[{'>','$2',3}],['$1']}]
這裡可以看到函數傳回的是一個比對規範,第一個參數第二個參數,大于号、第二個參數、具體的3,傳回第一個參數



3> X = 3,
ets:fun2ms(fun({M, N}) when N > X -> M end).
[{{'$1','$2'},[{'>','$2',{const,3}}],['$1']}]
也可以用外部變量,const就是全局常量



4> ets:fun2ms(fun({M, N}) when N > 3, is_atomm(M) -> M end).
* 1: illegal guard expression
這裡就報錯了,因為局部函數或全局函數是不能出現在函數的斷言裡的


5> ets:fun2ms(fun({M, N}) when N > 3, is_atom(M) -> M end).
[{{'$1','$2'},[{'>','$2',3},{is_atom,'$1'}],['$1']}]
内置函數可以被比對規範函數調用
           

延伸

這裡的4、5行裡when後面有一種可以一種不可以,這個在之前我有個朋友出現了類似的問題并且和我請教,當時印象有點深,因為這個點我也很模糊。when後面不能接自己寫的函數,但是内置的函數可以做條件

比如:

這裡用了内建函數,但是編譯的時候不能知道結果是以也不行,可以發現下面的代碼在IDEA裡敲完就直接報錯了

Erlang_ets冷門函數fun2ms

導師的解釋是when在比對後面必須要有确定的結果,編譯的時候就能知道結果的運算或者是NIF(Native Implemented Function)的。

NIF補充知識

在Erlang中,NIF(Native Implemented Function)被用來擴充erlang的某些功能,一般用來實作一些erlang很難實作的,或者一些erlang實作效率不高的功能。

NIF使用C開發,效率和C接近,比純erlang實作要高。NIF會編譯成動态庫,直接動态加載到erlang程序空間調用,也是erlang擴充新方法最高效的做法。調用NIF不用上下文的切換開銷,但是也有代價,NIF的crash會導緻整個Erlang程序crash。

我的了解是與NIF對立的就是我們熟悉的BIFs(Build-in Functions)内建函數,内建函數就是比如trunc直接erlang:trunc就可以調用的,常見的内建函數:

函數名 功能 函數名 功能
trunc 取整數部分 round 四舍五入
float 轉化為浮點數 is_atom 判斷是否為原子
is_tuple 判斷是否為元組 hd/1 傳回清單的第一個元素
tl/1 傳回清單的最後一個元素 length/1 傳回清單的長度
tuple_size/1 傳回元組大小 element/1 傳回第n個元組的元素
函數名 功能
setelement/3 替換元組中的某一個元素,并傳回新元組,setelement(要替換原子的位置,元組名,新原子的值)
erlang:append_element/2 添加一個原子到元組的末尾。(元組名,新原子的值)
類型轉換
atom_to_list 原子轉化為清單->字元串
list_to_atom 清單轉化為原子
integer_to_list 整數轉化為清單
list_to_tuple tuple_to_list
float,list_to_float float_to_list,integer_to_list

那這裡後面到底可以寫什麼?

  • 判斷資料類型(内建函數):is_binary, is_atom, is_boolean, is_tuple
  • 比較運算符:==, =/=, <, >…
  • 判斷語句: not, and, xor…

可以發現沒報錯的

Erlang_ets冷門函數fun2ms
Erlang_ets冷門函數fun2ms

可以發現複雜點的還是會報錯

Erlang_ets冷門函數fun2ms

回到fun2ms使用用法

和select搭配

我們發現ets:select/2中的參數為select(

Tab

,

MatchSpec

) -> [

Match

],這裡第二個參數可不就是咱fun2ms的傳回值嗎,

Erlang_ets冷門函數fun2ms

這不沖他

示例

1> ets:new(tab,[set,named_table]).
tab
2> ets:insert(tab,[{apple,1},{banana,2},{orange,3}]).
true
3> ets:fun2ms(fun({Key, Value} = Object) when Key =:= apple -> Object end).
[{{'$1','$2'},[{'=:=','$1',apple}],['$_']}]
4> Ms = ets:fun2ms(fun({Key, Value} = Object) when Key =:= apple -> Object end).
[{{'$1','$2'},[{'=:=','$1',apple}],['$_']}]
5> ets:select(tab, Ms).
[{apple,1}]
6> 
           

我對這個fun2ms的傳回值的了解是,提前給條件做一個判斷,這裡就是先設定Key=apple的類型的,然後比對Key、Value類型來做判斷,再作為select第二個參數傳入,發現确實能比對出對應Key==apple類型的

和match_spec_compile搭配

反正冷門了,不怕再冷門點,我們查API發現ets:match_spec_compile/1這個函數,傳入的參數也是MatchSpec,咋說,試下呗

match_spec_compile(MatchSpec) -> CompiledMatchSpec

測試發現傳回一個不認識的東西

1> MatchSpec = ets:fun2ms(fun({M, N}) when N > 3 -> M end),
ets:match_spec_compile(MatchSpec).
#Ref<0.1118727578.437125123.105226>
           

查表解釋為這個函數将一個比對規範MatchSpec轉換為一個可用于ets:match_sprc_run/2在後續調用的内部表示形式。轉換後的内部形式“不透明”的一個資料,并不能轉回為其原來的外部資料格式,并且完好無損的轉回。

示例

1> MatchSpec = ets:fun2ms(fun({M, N}) when N > 3 -> M end),
CompileMatchSpec = ets:match_spec_compile(MatchSpec).
#Ref<0.2741862248.2048524291.40502>
2> List = [{1,2},{3,4},{5,6}].
[{1,2},{3,4},{5,6}]
3> ets:match_spec_run(List,CompileMatchSpec).
[3,5]
4> 
           

越兜越複雜了哈,先看懂吧~

和is_compile_ms的搭配

還有個一起說下吧,這個函數主要是檢查已編譯的比對描述是否是有效的,

is_compiled_ms(Term) -> boolean()

示例

1> MatchSpec = ets:fun2ms(fun({M, N}) when N > 3 -> M end).
[{{'$1','$2'},[{'>','$2',3}],['$1']}]
2> Term = ets:match_spec_compile(MatchSpec).
#Ref<0.63853007.1514536963.50818>
3> ets:is_compiled_ms(Term).
true
4> ets:is_compiled_ms(MatchSpec).
false
5> 
           

可以看到隻有符合要求的傳回true,其他任意類型均傳回false