Regex的Bool方法调用未按文档描述工作的问题咨询
你这里的核心问题是混淆了Regex/子例程对象本身的Bool方法和匹配结果(Match对象)的Bool方法,加上对Raku中Regex调用机制的误解,才导致了不符合预期的结果。
1. 先理清my regex的实际行为
当你写my regex decimal { \d }时,Raku会同时创建两个东西:
- 一个
Regex类型的对象,用于描述匹配规则 - 一个同名的子例程
&decimal,这个子例程的逻辑是:自动使用当前作用域的$_作为匹配主题,执行正则匹配,最后返回一个Match对象(匹配成功时包含匹配细节,失败时返回一个"空"的Match对象)
2. 为什么&decimal.Bool返回False?
你调用的&decimal.Bool,是在询问子例程对象&decimal本身是否为真值,而不是执行匹配并返回结果。在Raku的部分版本中,子例程引用的Bool判断逻辑和你预期的不同,但更关键的是:这根本不是执行匹配的正确方式。
3. 正确的匹配与结果判断方式
要验证正则是否匹配$_(或指定字符串),你需要先执行匹配,再检查返回的Match对象的Bool值——这个值才会表示匹配是否成功:
方式一:直接调用子例程(自动匹配$_)
$_ = "3"; my regex decimal { \d }; say decimal.Bool; # 输出 True
这里的decimal()会自动用$_作为主题执行匹配,返回的Match对象的Bool方法会告诉你匹配是否成功。
方式二:显式指定匹配主题
my regex decimal { \d }; say decimal("3").Bool; # 输出 True
直接给子例程传递字符串,它会用这个字符串作为主题执行匹配。
方式三:使用智能匹配操作符~~
$_ = "3"; my regex decimal { \d }; say ($_ ~~ &decimal).Bool; # 输出 True
~~是Raku中用于模式匹配的标准操作符,左边是主题,右边是正则,返回的Match对象的Bool值表示匹配结果。
4. 关于$!topic实例变量的疑问
你在源码中看到的$!topic是Regex对象的内部属性,但它不会自动绑定全局的$_。只有当你通过上述几种方式执行匹配时,Regex对象才会将当前匹配的主题赋值给$!topic,用于后续的匹配逻辑。而Regex类自身的Bool方法,本质上只是检查对象自身的有效性(比如是否是一个合法的正则),并不会触发匹配操作——这也是你之前调用&decimal.Bool返回False的核心原因之一。
补充:文档描述的歧义
你看到的文档描述可能存在表述偏差,它真正想表达的应该是:当你调用regex声明的子例程时,会自动使用当前的$_作为匹配主题,而子例程返回的Match对象的Bool方法才会表示匹配是否成功,并非Regex类自身的Bool方法会主动去匹配$_。
内容的提问来源于stack exchange,提问作者jjmerelo

