正则表达式实际上是方法:
say rx/foo/.^mro # ((Regex) (Method) (Routine) (Block) (Code) (Any) (Mu))
在这种情况下,这意味着他们可以对自己采取行动,并且属于阶级的一部分。那班是什么?我的直觉是这是Match类,它们实际上是在$ /上作用(它们实际上是)。还有其他表达方式吗?
答案 0 :(得分:8)
最终,所有正则表达式都希望收到类型为Match
或Match
的某些子类的请求者。在Perl 6中,倡导者只是第一个论点,在任何其他方面都不特殊。
在软件包中用rule
,token
或regex
声明的那些正则表达式将作为该软件包中的方法安装。通常,它们是在grammar
中声明的,它只不过是其默认父级为class
而不是Grammar
的{{1}}。 Any
是Grammar
的子类型。
Match
因此很自然地将它们视为方法,但是主体使用不同的语言编写。实际上,这正是它们的本质。
要知道匿名正则表达式如何成为方法要困难一点,因为它们不会安装在任何类型的方法表中。但是,如果我们要写:
grammar G {}.^mro.say # ((G) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))
然后我们看到,即使此方法实际上未安装在类class C {
method foo() { 42 }
}
my $m = anon method () { self.foo }
say C.$m()
上,也可以通过self
解析该请求者的符号。匿名正则表达式也是如此。之所以如此重要,是因为C
,<ident>
,<.ws>
和朋友之类的断言实际上已编译为方法调用。
因此,匿名正则表达式是方法,因此将其第一个参数视为倡导者,才可以解决在<?before foo>
上声明的各种内置规则。
答案 1 :(得分:7)
方法不必与任何类相对应:
my method bar () { say self, '!' }
bar 'Hello World'; # Hello World!
my regex baz { :ignorecase 'hello world' }
'Hello World' ~~ /<baz>/;
'Hello World' ~~ &baz;
&baz.ACCEPTS('Hello World'); # same as previous line
# baz 'Hello World';
默认情况下,通过扩展名,正则表达式与它们在其中声明的任何类都具有has
关系。
class Foo {
method bar () { say self, '!' }
# has method bar () { say self, '!' }
regex baz { :ignorecase 'hello world' }
# has regex baz () { :ignorecase 'hello world' }
}
正则表达式的确需要满足一些要求,无论其要求是什么。
通过将其作为子例程运行,它会告诉您第一个:
my regex baz { :ignorecase 'hello world' }
baz 'Hello World';
No such method '!cursor_start' for invocant of type 'Str'
in regex baz at <unknown file> line 1
in block <unit> at <unknown file> line 1
通常,在用grammar
声明的类中声明正则表达式。
grammar Foo {
}
say Foo.^mro;
# ((Foo) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))
因此,在这种情况下,可能需要Grammar
,Match
或Capture
来满足要求。
它也可能来自与之融为一体的角色。
say Foo.^roles.map(*.^name);
# (NQPMatchRole)
甚至更有理由相信它是Match
或Capture
my regex baz {
^
{ say 'baz was called on: ', self.^name }
}
&baz.ACCEPTS(''); # baz was called on: Match
my regex baz ( $s ) {
:ignorecase
"$s"
}
baz Match.new(orig => 'Hello World'), 'hello';
# 「Hello」
我看不出有人在普通班级还是不能这样做。
请注意,$/
只是一个变量。因此,说将其传递给正则表达式是对情况的误解。
my regex baz ( $/ ) {
:ignorecase
"$/"
}
'Hello World' ~~ /<baz('hello')>/;
# 「Hello」
# baz => 「Hello」
准确地说,当从另一个内部调用正则表达式时,当前的$/
用作方法/正则表达式的调用者。
(我不完全确定这是否会发生。)
因此,前面的示例将像这样:
'Hello World' ~~ /{ $/.&baz('hello') }/;
答案 2 :(得分:3)
这种解释结合了我认为Brad ++和Jonathan ++刚刚教给我的知识,以为我已经知道的知识以及进一步挖掘后发现的知识。
(我的最初目标是直接解释Brad神秘的No such method '!cursor_start'
信息。我现在已经失败了,只是提交了a bug report,但这就是我的最终目的。)
方法被设计为在类中自然工作。实际上,没有作用域声明符的方法声明假定has
-并且has
声明属于一个类:
method bar {} # Useless declaration of a has-scoped method in mainline
但是实际上方法也可以很好地工作:
sub
s(即不完全表现为面向对象的方法);或
prototype-based programming的方法(即,面向对象,但没有类)。
真正使方法成为方法的是它们是带有"invocant"的例程。倡导者是特殊的状态优先参数,
Mu
: class foo { my method bar {} .signature .say } # (foo: *%_)
my method bar {} .signature .say # (Mu: *%_)
my method bar {}
bar # Too few positionals passed; expected 1 argument but got 0
self
。因此: my method bar { say self }
bar 42 # 42
:
)来明确声明。因此:
my method bar (Int \baz:) { say baz }
say &bar.signature; # (Int \baz: *%_)
bar 42; # 42
bar 'string'; # Type check failed in binding to parameter 'baz'
正则表达式是仅以激进者为视角的方法,它采用/期望匹配对象作为激进者。
正则表达式通常在三种不同的情况下被调用:
直接使用。例如my regex foo { . }; say 'a' ~~ &foo; # 「a」
(或仅say 'a' ~~ / . /; # 「a」
,但为了简化说明,我将仅介绍基本相同的命名示例)。这将转换为say &foo.ACCEPTS: 'a'
。这就是implemented by this code in Rakudo。如您所见,这将以正则表达式foo
-which runs this code而不使用Match.'!cursor_init'(...)
来调用正则表达式:build
。结果是foo
得到了一个新的Match
对象作为其发起人。
通过Grammar
类的.parse
方法。 The .parse
method创建语法的新实例,然后将顶部的“规则”称为(rule
/ token
/ regex
/ method
)上的新语法对象。请注意,Grammar
是Match
的子类;因此,就像第一种情况一样,正在将规则/正则表达式传递为一个空匹配对象。如果最高规则匹配,则对.parse
的调用将返回新的语法/匹配对象。 (否则它将返回Nil
。)
通过上述方式之一。语法中的最高规则通常包含对较低级别的规则/令牌/正则表达式/方法的调用。同样,独立规则/正则表达式可能包含对其他规则/正则表达式的调用。每个此类调用将涉及创建另一个新的语法/匹配对象,该对象成为嵌套调用的发起者。如果嵌套调用匹配并且是捕获调用,则新的语法/匹配对象将添加到更高级别的语法/匹配对象。