Scala Regex unapplySeq模式匹配为何可编译且不抛运行时错误?
为什么这段Scala代码可以正常编译且无运行时错误
问题涉及的代码如下:
val regex = raw"a*".r def matchRegex(str: String): Boolean = str match { case regex("abc") => true case _ => false }
核心原因
这段代码的表现是Scala提取器(Extractor)模式匹配规则、Regex类的提取器实现共同决定的:
raw"a*".r生成的是scala.util.matching.Regex实例,该类实现了unapplySeq方法以支持模式匹配:case分支中调用regex(...)时,编译器会自动调用该方法传入待匹配字符串:如果字符串整体不符合正则规则,直接返回None表示匹配失败;如果符合正则规则,会将正则内所有捕获组匹配到的内容按顺序组装为Seq[String]返回。regex("abc")是完全合法的提取器语法:编译器不会校验括号内传入的是字面量还是通配符,只要参数类型和捕获组返回的序列元素类型兼容(此处均为String,完全匹配)即可通过编译。该写法的实际匹配逻辑是:只有unapplySeq返回的序列**恰好等于Seq("abc")**时,才会进入当前分支。- 示例中定义的正则
a*没有声明任何捕获组,因此只要字符串匹配该正则,unapplySeq返回的永远是空序列Seq(),不可能等于Seq("abc"),因此该分支永远不会命中,代码始终走兜底分支返回false。整个过程既无语法问题,运行时也仅做普通的序列相等判断,自然不会抛出错误。
补充说明
你提到的常规写法regex(_*)本质是对捕获组返回序列做全通配:只要正则匹配成功,无论捕获组返回什么内容都直接进入分支,和传入固定字符串字面量做精确捕获值匹配的写法在语法层面完全一致,仅匹配条件不同。
如果将正则修改为带捕获组的版本,比如val regex = raw"(a*)".r,当输入为全a组成的字符串时,unapplySeq会返回长度为1的序列(内容为捕获到的全a子串),此时写case regex("aaa"),输入恰好为"aaa"时就会成功命中分支返回true。
内容的提问来源于stack exchange,提问作者Devigny
相关产品推荐
相关产品推荐

