Perl6 Grammar语法规则命名的元对象规则及命名冲突疑问
这确实是Perl 6 Grammar里一个挺让人头疼的命名陷阱,我来帮你理清楚这里面的门道:
冲突的两类典型情况
和
sub类型的核心方法重名:比如item(属于Any类的sub),当你把它定义成token时,Perl 6会优先调用继承来的sub item而不是你的token,而这个sub需要参数,匹配时却没有传参,就会抛出Too many positionals passed的错误。
示例代码:grammar g { token TOP { <item> }; token item { 'defined' } }; say g.parse('defined');报错:
Too many positionals passed; expected 1 argument but got 2和BUILD、TWEAK这类特殊子方法重名:这两个是对象构造阶段的钩子方法,当你用它们做token名时,调用逻辑会混乱,抛出
Cannot find method 'match'的错误。
为什么有些同名方法没问题?
这是因为Perl 6的方法解析优先级和方法类型有关:
- 多数
multi或普通method类型的核心方法(比如rand),在Grammar上下文里,规则的调用优先级更高,所以不会冲突; FALLBACK虽然是子方法,但它的作用是处理未定义的方法调用,所以当你定义了同名token时,会优先使用你的规则,而不是触发FALLBACK逻辑;- 至于
CREATE(method类型)却会冲突,这是因为它是Grammar继承链里的特殊构造方法,优先级更高,导致你的token被忽略。
怎么规避这类问题?
- 提前避开高危名称:优先避免使用Any、Cool、Match等核心类中标记为
sub的方法名,以及BUILD、TWEAK这类构造钩子; - 测试验证:如果不确定某个名称是否安全,写个最小测试用例验证,比如:
如果能正常输出匹配结果,说明这个名称没问题;grammar TestGrammar { token TOP { <test-name> }; token test-name { 'test' } }; say TestGrammar.parse('test'); - 显式指定规则:如果必须使用冲突名称,可以用
::强制指定调用当前Grammar的规则,比如:
这样就能绕过继承的方法,调用你定义的token了。grammar g { token TOP { <::item> }; token item { 'defined' } }; say g.parse('defined');
内容的提问来源于stack exchange,提问作者jjmerelo
相关产品推荐
相关产品推荐

