4.在Erlang中匹配规范 | 4. Match Specifications in Erlang
4 Erlang中的匹配规格
“匹配规范”(match_spec
)是一个Erlang术语,描述了一个试图匹配某个东西的小程序。例如,它可用于控制跟踪erlang:trace_pattern/3
或在ETS表中搜索对象ets:select/2
。在很多方面,匹配规范在Erlang中都像一个小函数,但是被Erlang运行时系统解释/编译为比调用Erlang函数更有效。与真正的Erlang函数的表现力相比,匹配规范也非常有限。
匹配规范和Erlang 函数之间最显着的区别是语法。匹配规范是Erlang条款,而不是Erlang代码。另外,匹配规范有一个奇怪的异常概念:
badarg
该MatchCondition
部分中的例外情况(类似于Erlang警卫)会立即生成失败。
4.1语法
跟踪中使用的匹配规范可以用以下非正式
语法来描述:
- MatchExpression ::= MatchFunction, ...
ets(3)
在以下非正式
语法中可以描述使用的匹配规范:
- MatchExpression ::= MatchFunction, ...
4.2功能描述
在所有类型的匹配规范中允许的功能
允许的函数match_spec
如下:
is_atom
**
,**
is_float
**
,**
is_integer
**
,**
is_list
**
,**
is_number
**
,**
is_pid
**
,**
is_port
**
,**
is_reference
**
,**
is_tuple
**
,**
is_map
**
,**
is_binary
**
,**
is_function
与Erlang中相应的守卫测试相同,返回true
或false
。
is_record
需要一个附加的参数,该参数必须是的结果record_info(size, <record_type>),像{is_record, '$1', rectype, record_info(size, rectype)}。
'not'
否定其单一论点(除了false
给出的东西false
)。
'and'
返回true
如果其所有参数(可变长度参数列表)来评估true
,否则false
。评估订单未定义。
'or'
返回true
其任何参数的计算结果true
。可变长度参数列表。评估订单未定义。
'andalso'
作为'and'
,但是当一个论证评估为别的东西时退出评估它的论点true
。参数从左到右进行评估。
'orelse'
作为'or'
,但一旦其论据评估结果就立即停止评估true
。参数从左到右进行评估。
'xor'
只有两个参数,其中一个必须是true
与其他false
返回true
; 否则'xor'
返回false
。
abs**,* element**,** hd**,** length**,** node**,** round**,** size**,** tl**,** trunc**,** '+'**,** '-'**,** **`''****,** **'div'****,** **'rem'****,** **'band'****,** **'bor'****,** **'bxor'****,** **'bnot'****,** **'bsl'****,** **'bsr'****,** **'>'****,** **'>='****,** **'<'****,** **'=<'****,** **'=:='****,** **'=='****,** **'=/='****,** **'/='****,** **self`**
与相应的Erlang BIF(或运营商)相同。如果参数错误,结果取决于上下文。在MatchConditions
表达部分,测试立即失败(就像Erlang的警卫)。在该MatchBody
部分中,异常被隐式捕获,并且调用导致原子'EXIT'
。
仅允许跟踪的函数
这些函数仅用于跟踪工作,如下所示:
is_seq_trace
如果为当前进程设置了顺序跟踪令牌,则返回true
;否则返回false
。
set_seq_token
作为seq_trace:set_token/2
,但成功返回true
,'EXIT'
错误或错误的论点。只允许在MatchBody
零件中使用,且仅在追踪时允许。
get_seq_token
跟踪时相同seq_trace:get_token/0
且只允许在该MatchBody
部分中。
message
设置附加到发送的跟踪消息的附加消息。人们只能在正文中设置一条附加信息。稍后调用替换附加的消息。
作为一种特殊情况,{message, false}
禁止为该函数调用发送跟踪消息('call'和'return_to'),就像匹配规范不匹配一样。如果只MatchBody
需要零件的副作用,这可能很有用。
另一个特殊情况是{message, true}
,它设置默认行为,就好像该函数没有匹配规范一样; 跟踪消息是,没有额外的信息(如果没有其他调用发送message
的前放置{message, true}
,它实际上是一个“空指令”)。
采取一个论据:消息。返回true
并且只能在MatchBody
零件和跟踪时使用。
return_trace
导致return_from
从当前函数返回时发送跟踪消息。不带参数,返回true
,只能MatchBody
在追踪时使用。如果进程跟踪标志silent
处于活动状态,则return_from
跟踪消息被禁止。
警告:
如果跟踪的函数是尾递归的,则此匹配规范函数将销毁该属性。因此,如果在永久服务器进程中使用执行此功能的匹配规范,则它只能在有限的时间内处于活动状态,否则仿真器将最终使用主机中的所有内存并崩溃。如果使用进程跟踪标志禁止该匹配指定函数silent
,则尾递归仍然存在。
exception_trace
作为return_trace
; 如果由于异常而导致跟踪的函数退出,exception_from
则会生成跟踪消息,而不管异常是否被捕获。
process_dump
以二进制形式返回有关当前进程的一些文本信息。不带任何参数,只有在MatchBody
追踪时才允许使用。
enable_trace
有了一个参数,这个函数就会像Erlang调用一样打开跟踪erlang:trace(self(), true, [P2])
,其中P2
的参数是enable_trace
。
使用两个参数时,第一个参数是进程标识符或进程的注册名称。在这种情况下,跟Erlang调用一样,指定进程的跟踪被打开erlang:trace(P1, true, [P2])
,其中P1
第一个P2
参数是第二个参数。该进程P1
获取跟踪执行语句使用的跟踪消息。P1
不能
是原子之一all
,new
或者existing
(除非它们是注册名称)。P2
不能
是cpu_timestamp
或tracer
。
返回true
,只能在使用MatchBody
部分进行跟踪时。
disable_trace
使用一个参数,该函数禁用Erlang调用之类的跟踪erlang:trace(self(), false, [P2])
,其中P2
参数为disable_trace
。
有两个参数,这个函数作为Erlang调用工作erlang:trace(P1, false, [P2])
,其中P1
可以是进程标识符或注册名称,并被指定为匹配规范函数的第一个参数。P2
不能
是cpu_timestamp
或tracer
。
返回true
,只能在使用MatchBody
部分进行跟踪时。
trace
使用两个参数时,此函数会将一系列跟踪标志禁用为第一个参数,并将一系列跟踪标志作为第二个参数启用。逻辑上,首先应用禁用列表,但实际上所有更改都是以原子方式应用的。跟踪标志与for相同erlang:trace/3
,不包括cpu_timestamp
,但包括tracer
。
如果在两个列表中都指定了跟踪器,则启用列表中的跟踪器优先。如果没有指定跟踪器,则使用与执行匹配规范的过程相同的跟踪器。
当使用tracer module
时,模块必须在执行匹配规格之前加载。如果未加载,则匹配失败。
使用此函数的三个参数,第一个参数是进程标识符或用于设置跟踪标志的进程的注册名称,第二个参数是禁用列表,第三个参数是启用列表。
如果跟踪目标进程的任何跟踪属性已更改,则返回true
,否则返回false
。MatchBody
跟踪时只能用在零件中。
caller
如果无法确定调用函数,则将调用函数作为元组{Module, Function, Arity}
或原子返回undefined
。MatchBody
跟踪时只能用在零件中。
请注意,如果追踪“技术上内置的函数”(即,不是用Erlang编写的函数),该caller
函数有时会返回原子undefined
。调用Erlang函数在这种调用中不可用。
display
仅用于调试目的。将单个参数显示为Erlang术语stdout
,这很少需要。返回true
,只能在使用MatchBody
部分进行跟踪时。
get_tcw
不参数并返回节点的跟踪控制字的值。同样的事情由erlang:system_info(trace_control_word)
。
跟踪控制字是一个用于通用跟踪控制的32位无符号整数。跟踪控制字可以从跟踪匹配规范和BIF中进行测试和设置。此调用仅在跟踪时才被允许。
set_tcw
取一个无符号整数参数,将节点的跟踪控制字的值设置为参数的值,并返回前一个值。同样的事情由erlang:system_flag(trace_control_word, Value)
。追踪时只允许set_tcw
在MatchBody
零件中使用。
silent
拿一个参数。如果参数是true
,则当前进程的呼叫跟踪消息模式被设置为对于该呼叫的无声,并且即使{message, true}
在MatchBody
部件中为被跟踪的功能调用了所有稍后的呼叫,即呼叫跟踪消息也被禁止。
这个模式也可以用flag silent
来激活erlang:trace/3
。
如果参数是false
,则当前进程的呼叫追踪消息模式被设置为正常(非静默),用于此呼叫和所有稍后的呼叫。
如果参数不是true
或false
,则呼叫跟踪消息模式不受影响。
注意
所有的“函数调用”都必须是元组,即使它们没有参数。它的值self
是atom()self
,但其值{self}
是当前进程的pid()。
4.3匹配目标
匹配规范的每次执行都是针对匹配目标术语完成的。目标词的格式和内容取决于匹配完成的上下文。ETS的匹配目标始终是全表元组。调用跟踪的匹配目标始终是所有函数参数的列表。事件跟踪的匹配目标取决于事件类型,请参见下表。
上下文 | 类型 | 匹配目标 | 描述 |
---|---|---|---|
ETS | | {Key,Value1,Value2,...} | 一个表格对象 |
跟踪 | 呼叫 | Arg1,Arg2,... | 函数参数 |
跟踪 | 发送 | 接收者,消息 | 接收过程/端口和消息术语 |
跟踪 | '接收' | 节点,发件人,消息 | 发送节点,进程/端口和消息术语 |
4.4变量和文字
变量采用表格'$<number>',其中<number>是一个介于0和100,000,000之间的整数(1e + 8)。数字超出这些限制的行为未定义。在MatchHead部分中,特殊变量'_'匹配任何东西,并且永远不会被绑定(就像_在Erlang中)。
- 在这些
MatchCondition/MatchBody
部分中,不允许任何未绑定的变量,所以'_'
被解释为它自己(一个原子)。变量只能在MatchHead
部分中绑定。
- The variable `'$_'` expands to the whole [`match target`](about:blank#match_target) term.
- The variable `'$$'` expands to a list of the values of all bound variables in order (that is, `['$1','$2', ...]`).
在MatchHead
部分中,所有文字(除了上面的变量)都被解释为“原样”。
在这些MatchCondition/MatchBody
部分中,解释在某些方面是不同的。这些部分中的文字可以写成“as is”,它适用于除元组以外的所有文字,或者使用特殊形式{const, T}
,其中T
任何Erlang术语。
对于匹配规范中的元组文字,也可以使用双元组圆括号,即将它们构造为一个包含单个元组的元组的元组,它是要构造的元组。“双元组圆括号”语法对于从已经绑定的变量中构造元组很有用,就像in {{'$1', [a,b,'$2']}}
。例子:
表达 | 变量绑定 | 结果 |
---|---|---|
{{'$1','$2'}} | '$1' = a, '$2' = b | {a,b} |
{const, {'$1', '$2'}} | Irrelevant | {'$1', '$2'} |
a | Irrelevant | a |
'$1' | '$1' = [] | [] |
'$1' | '$1' = [] | [[]] |
{{a}} | Irrelevant | {a} |
42 | Irrelevant | 42 |
"hello" | Irrelevant | "hello" |
$1 | Irrelevant | 49 (the ASCII value for character '1') |
4.5匹配的执行
当运行时系统决定是否发送跟踪消息时,执行匹配表达式如下:
对于MatchExpression
列表中的每个元组,当没有匹配成功时:
- 匹配MatchHead部分与匹配目标术语,绑定'$<number>'变量(非常类似于ets:match/2)。如果MatchHead零件不能匹配参数,则匹配失败。
- 如果匹配规范在跟踪时正在执行:按照与之ActionTerm相同的方式评估每个规则MatchConditions,但忽略返回值。无论这部分发生了什么,比赛都成功了。
- 如果在从ETS表中选择对象时执行匹配规范:按顺序评估表达式并返回最后一个表达式的值(通常在此上下文中只有一个表达式)。
4.6 ETS和跟踪中匹配规格的区别
ETS匹配规格产生返回值。通常MatchBody
包含一个ConditionExpression
定义返回值而没有任何副作用的单个。在ETS环境中不允许带副作用的呼叫。
当追踪没有产生返回值时,匹配规范匹配或不匹配。表达式匹配时的效果是跟踪消息而不是返回的术语。该ActionTerm
s的在命令式语言,那就是,对于其副作用执行。跟踪时也允许带副作用的函数。
4.7跟踪示例
匹配三个参数列表,其中第一个和第三个参数相等:
[{['$1', '_', '$1'],
[],
[]}]
匹配三个参数列表,其中第二个参数是数字> 3:
[{['_', '$1', '_'],
[{ '>', '$1', 3}],
[]}]
匹配三个参数列表,其中第三个参数是包含参数1和2的元组,或者
以参数1和2(即[a,b,[a,b,c]]
或[a,b,{a,b}]
)开头的列表:
[{['$1', '$2', '$3'],
[{'orelse',
{'=:=', '$3', {{'$1','$2'}}},
{'and',
{'=:=', '$1', {hd, '$3'}},
{'=:=', '$2', {hd, {tl, '$3'}}}}}],
[]}]
上述问题也可以如下解决:
[{['$1', '$2', {'$1', '$2}], [], []},
{['$1', '$2', ['$1', '$2' | '_']], [], []}]
匹配两个参数,其中第一个是以第二个参数乘以2开头的列表(即:[{[4,x],y},2]
或者[{[8], y, z},4])
:
[{['$1', '$2'],[{'=:=', {'*', 2, '$2'}, {hd, {element, 1, '$1'}}}],
[]}]
匹配三个参数。当所有三者相等并且都是数字时,将进程转储附加到跟踪消息,否则让跟踪消息“按原样”,但将顺序跟踪令牌标签设置为4711:
[{['$1', '$1', '$1'],
[{is_number, '$1'}],
[{message, {process_dump}}]},
{'_', [], [{set_seq_token, label, 4711}]}]
如上所述,参数列表可以匹配单个MatchVariable
或一个'_'
。用单个变量替换整个参数列表是一种特殊情况。在所有其他情况下,MatchHead
必须是适当的
清单。
仅在跟踪控制字设置为1时才生成跟踪消息:
[{'_',
[{'==',{get_tcw},{const, 1}}],
[]}]
仅在存在seq_trace
令牌时才生成跟踪消息:
[{'_',
[{'==',{is_seq_trace},{const, 1}}],
[]}]
'silent'
当第一个参数是移除跟踪标志'verbose'
,并添加它时,它是'silent':
[{'$1',
[{'==',{hd, '$1'},verbose}],
[{trace, [silent],[]}]},
{'$1',
[{'==',{hd, '$1'},silent}],
[{trace, [],[silent]}]}]
return_trace
如果函数的参数为3,则添加一条消息:
[{'$1',
[{'==',{length, '$1'},3}],
[{return_trace}]},
{'_',[],[]}]
仅当函数的参数为3且第一个参数为'trace'
:时,才会生成跟踪消息:
[{['trace','$2','$3'],
[],
[]},
{'_',[],[]}]
4.8 ETS示例
匹配ETS表中的所有对象,其中第一个元素是原子'strider'
,元组参数是3,并返回整个对象:
[{{strider,'_','_'},
[],
['$_']}]
将ETS表中的所有对象与arity> 1匹配,第一个元素为'gandalf',并返回元素2:
[{'$1',
[{'==', gandalf, {element, 1, '$1'}},{'>=',{size, '$1'},2}],
[{element,2,'$1'}]}]
在这个例子中,如果第一个元素是关键字,那么在MatchHead
零件中匹配该关键字要比在MatchConditions
零件中匹配效率高得多。表中的搜索空间受到限制,MatchHead
以便只搜索具有匹配键的对象。
匹配三个元素的元组,其中第二个元素是'merry'
或'pippin'
,并返回整个对象:
[{{'_',merry,'_'},
[],
['$_']},
{{'_',pippin,'_'},
[],
['$_']}]
函数ets:test_ms/2>可用于测试复杂的ETS匹配。