非常教程

Erlang 20参考手册

指南:ERTS | Guide: ERTS

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代码。另外,匹配规范有一个奇怪的异常概念:

  • badargMatchCondition部分中的例外情况(类似于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中相应的守卫测试相同,返回truefalse

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 不能是原子之一allnew或者existing(除非它们是注册名称)。P2 不能cpu_timestamptracer

返回true,只能在使用MatchBody部分进行跟踪时。

disable_trace

使用一个参数,该函数禁用Erlang调用之类的跟踪erlang:trace(self(), false, [P2]),其中P2参数为disable_trace

有两个参数,这个函数作为Erlang调用工作erlang:trace(P1, false, [P2]),其中P1可以是进程标识符或注册名称,并被指定为匹配规范函数的第一个参数。P2 不能cpu_timestamptracer

返回true,只能在使用MatchBody部分进行跟踪时。

trace

使用两个参数时,此函数会将一系列跟踪标志禁用为第一个参数,并将一系列跟踪标志作为第二个参数启用。逻辑上,首先应用禁用列表,但实际上所有更改都是以原子方式应用的。跟踪标志与for相同erlang:trace/3,不包括cpu_timestamp,但包括tracer

如果在两个列表中都指定了跟踪器,则启用列表中的跟踪器优先。如果没有指定跟踪器,则使用与执行匹配规范的过程相同的跟踪器。

当使用tracer module时,模块必须在执行匹配规格之前加载。如果未加载,则匹配失败。

使用此函数的三个参数,第一个参数是进程标识符或用于设置跟踪标志的进程的注册名称,第二个参数是禁用列表,第三个参数是启用列表。

如果跟踪目标进程的任何跟踪属性已更改,则返回true,否则返回falseMatchBody跟踪时只能用在零件中。

caller

如果无法确定调用函数,则将调用函数作为元组{Module, Function, Arity}或原子返回undefinedMatchBody跟踪时只能用在零件中。

请注意,如果追踪“技术上内置的函数”(即,不是用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_tcwMatchBody零件中使用。

silent

拿一个参数。如果参数是true,则当前进程的呼叫跟踪消息模式被设置为对于该呼叫的无声,并且即使{message, true}MatchBody部件中为被跟踪的功能调用了所有稍后的呼叫,即呼叫跟踪消息也被禁止。

这个模式也可以用flag silent来激活erlang:trace/3

如果参数是false,则当前进程的呼叫追踪消息模式被设置为正常(非静默),用于此呼叫和所有稍后的呼叫。

如果参数不是truefalse,则呼叫跟踪消息模式不受影响。

注意

所有的“函数调用”都必须是元组,即使它们没有参数。它的值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部分中绑定。
  • MatchBodyMatchCondition部分中,只能使用先前绑定的变量。
  • 作为特例,以下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匹配。

Erlang 20

Erlang 是一种通用的面向并发的编程语言,可应付大规模开发活动的程序设计语言和运行环境。

主页 https://www.erlang.org/
源码 https://github.com/erlang/otp
版本 20
发布版本 20.1