4.在Erlang中匹配规范 | 4. Match Specifications in Erlang
“匹配规范”(match_spec)是一个Erlang术语,描述了一个试图匹配某个东西的小程序。例如,它可用于控制跟踪erlang:trace_pattern/3或在ETS表中搜索对象ets:select/2。在很多方面,匹配规范在Erlang中都像一个小函数,但是被Erlang运行时系统解释/编译为比调用Erlang函数更有效。与真正的Erlang函数的表现力相比,匹配规范也非常有限。
匹配规范和Erlang 函数之间最显着的区别是语法。匹配规范是Erlang条款,而不是Erlang代码。另外,匹配规范有一个奇怪的异常概念:
badarg该MatchCondition部分中的例外情况(类似于Erlang警卫)会立即生成失败。- 该
MatchBody部分中的一个例外,类似于Erlang函数的主体,被隐式捕获并导致单个原子'EXIT'。
4.1语法
跟踪中使用的匹配规范可以用以下非正式语法来描述:
- MatchExpression ::= MatchFunction, ...
- MatchFunction ::= { MatchHead, MatchConditions, MatchBody }
- MatchHead ::= MatchVariable |
'_'| MatchHeadPart, ... - MatchHeadPart ::= term() | MatchVariable |
'_' - MatchVariable ::= '$<number>'
- MatchConditions ::= MatchCondition, ... |
[] - MatchCondition ::= { GuardFunction } | { GuardFunction, ConditionExpression, ... }
- BoolFunction ::=
is_atom|is_float|is_integer|is_list|is_number|is_pid|is_port|is_reference|is_tuple|is_map|is_binary|is_function|is_record|is_seq_trace|'and'|'or'|'not'|'xor'|'andalso'|'orelse' - ConditionExpression ::= ExprMatchVariable | { GuardFunction } | { GuardFunction, ConditionExpression, ... } | TermConstruct
- ExprMatchVariable ::= MatchVariable (bound in the MatchHead) |
'$_'|'$$' - TermConstruct = {{}} | {{ ConditionExpression, ... }} |
[]| ConditionExpression, ... |#{}| #{term() => ConditionExpression, ...} | NonCompositeTerm | Constant - NonCompositeTerm ::= term() (not list or tuple or map)
- Constant ::= {
const, term()} - GuardFunction ::= BoolFunction |
abs|element|hd|length|node|round|size|tl|trunc|'+'|'-'|'*'|'div'|'rem'|'band'|'bor'|'bxor'|'bnot'|'bsl'|'bsr'|'>'|'>='|'<'|'=<'|'=:='|'=='|'=/='|'/='|self|get_tcw - MatchBody ::= ActionTerm
- ActionTerm ::= ConditionExpression | ActionCall
- ActionCall ::= {ActionFunction} | {ActionFunction, ActionTerm, ...}
- ActionFunction ::=
set_seq_token|get_seq_token|message|return_trace|exception_trace|process_dump|enable_trace|disable_trace|trace|display|caller|set_tcw|silent
ets(3)在以下非正式语法中可以描述使用的匹配规范:
- MatchExpression ::= MatchFunction, ...
- MatchFunction ::= { MatchHead, MatchConditions, MatchBody }
- MatchHead ::= MatchVariable |
'_'| { MatchHeadPart, ... } - MatchHeadPart ::= term() | MatchVariable |
'_' - MatchVariable ::= '$<number>'
- MatchConditions ::= MatchCondition, ... |
[] - MatchCondition ::= { GuardFunction } | { GuardFunction, ConditionExpression, ... }
- BoolFunction ::=
is_atom|is_float|is_integer|is_list|is_number|is_pid|is_port|is_reference|is_tuple|is_map|is_binary|is_function|is_record|is_seq_trace|'and'|'or'|'not'|'xor'|'andalso'|'orelse' - ConditionExpression ::= ExprMatchVariable | { GuardFunction } | { GuardFunction, ConditionExpression, ... } | TermConstruct
- ExprMatchVariable ::= MatchVariable (bound in the MatchHead) |
'$_'|'$$' - TermConstruct = {{}} | {{ ConditionExpression, ... }} |
[]| ConditionExpression, ... | #{} | #{term() => ConditionExpression, ...} | NonCompositeTerm | Constant - NonCompositeTerm ::= term() (not list or tuple or map)
- Constant ::= {
const, term()} - GuardFunction ::= BoolFunction |
abs|element|hd|length|node|round|size|tl|trunc|'+'|'-'|'*'|'div'|'rem'|'band'|'bor'|'bxor'|'bnot'|'bsl'|'bsr'|'>'|'>='|'<'|'=<'|'=:='|'=='|'=/='|'/='|self|get_tcw - MatchBody ::= ConditionExpression, ...
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部分中绑定。 - 在
MatchBody和MatchCondition部分中,只能使用先前绑定的变量。 - 作为特例,以下
MatchCondition/MatchBody部分适用于:
- 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零件不能匹配参数,则匹配失败。 - 评估每个
MatchCondition(只有'$<number>'先前在MatchHead零件中绑定的变量才会发生),并期望它返回原子true。当条件不符合时true,匹配失败。如果任何BIF调用产生异常,则匹配也会失败。 - 可能会发生两种情况:
- 如果匹配规范在跟踪时正在执行:按照与之ActionTerm相同的方式评估每个规则MatchConditions,但忽略返回值。无论这部分发生了什么,比赛都成功了。 - 如果在从ETS表中选择对象时执行匹配规范:按顺序评估表达式并返回最后一个表达式的值(通常在此上下文中只有一个表达式)。4.6 ETS和跟踪中匹配规格的区别
ETS匹配规格产生返回值。通常MatchBody包含一个ConditionExpression定义返回值而没有任何副作用的单个。在ETS环境中不允许带副作用的呼叫。
当追踪没有产生返回值时,匹配规范匹配或不匹配。表达式匹配时的效果是跟踪消息而不是返回的术语。该ActionTerms的在命令式语言,那就是,对于其副作用执行。跟踪时也允许带副作用的函数。
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匹配。
本文档系腾讯云开发者社区成员共同维护,如有问题请联系 cloudcommunity@tencent.com

