如何在scala 2中添加扩展方法到单例对象?



我偶然发现了这个线程,@prolativ提供了一些花哨的scala 3语法来为对象创建扩展方法

extension (int: Int.type)
def unapply(s: String): Option[Int] = s.toIntOption

但是这让我想到如果有一种方法可以在scala 2中做类似的事情?

我试过了

implicit class IntOps(s: Int.type) {
def unapply(s: String): Option[Int] = s.toIntOption
}

这似乎只是scala 2的翻译,但它不会编译错误object Int is not a case class, nor does it have a valid unapply/unapplySeq member.

乌利希期刊指南在模式匹配的情况下,有一种方法可以做到这一点-只需添加新对象并匹配它:

object IntOps {
def unapply(s: String): Option[Int] = s.toIntOption
}

,但问题仍然存在-如何添加扩展方法的对象?

隐式类是向对象添加扩展方法的正确方法

implicit class IntOps(obj: Int.type) {
def parse(s: String): Option[Int] = s.toIntOption
}
Int.parse("123") // Some(123)

unapply可以用同样的方法加入

implicit class IntOps(obj: Int.type) {
def unapply(s: String): Option[Int] = s.toIntOption
}
Int.unapply("123") // Some(123)

这对模式匹配没有影响

"123" match {
case Int(i) => ??? // doesn't compile: object Int is not a case class, nor does it have a valid unapply/unapplySeq member
}

Scala 2编译器抛出object Int is not a case class, nor does it have a valid unapply/unapplySeq member的地方在这里:https://github.com/scala/scala/blob/v2.13.10/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala L121-L122

else if (!reallyExists(member))
CaseClassConstructorError(fun, s"${fun.symbol} is not a case class, nor does it have a valid unapply/unapplySeq member")

这是基于符号(scala-reflect术语中的typeOf[Int.type].decl(TermName("unapply")))。这里不检查隐式转换(扩展方法)。

这在Scala 3中被修改:https://github.com/lampepfl/dotty/blob/3.2.2/compiler/src/dotty/tools/dotc/typer/Applications.scala#L1291-L1341编译器尝试对x.unapply进行类型检查,这包括隐式转换。

顺便说一下,当Scala 2编译器决定是否在case的伴侣对象中生成unapply时类(Int不是case类)编译器也不检查扩展方法

如何查看Scala用于自动生成case类的apply函数的代码?

case class MyClass(i: Int)
MyClass(42) match {
case MyClass(i) => println(i) // 42
}
case class MyClass(i: Int)
object MyClass {
def unapply(mc: MyClass): Option[Int] = Some(100)
}
MyClass(42) match {
case MyClass(i) => println(i) // 100
}
case class MyClass(i: Int)
implicit class MyClassCompanionOps(mc: MyClass.type) {
def unapply(mc: MyClass): Option[Int] = Some(100)
}
MyClass(42) match {
case MyClass(i) => println(i) // 42
}

这个行为在Scala 3中也是一样的。


如何扩展字符串以添加新的unapply函数以用于提取?

用unapply功能充实PartialFunction