scala Stack Overflow in implicit object 未应用

scala StackOverflow on implicit object unapply

我正在编写一个类型类来在类型之间进行转换,我注意到隐式对象上的 unapply 方法有些不寻常。具体

object IntString extends PartialFunction[String, Int] {
  def isDefinedAt(x: String) = Try(x.toInt).isSuccess
  def apply(v1: String) = v1.toInt
  def unapply(a:String):Option[Int] = if(this.isDefinedAt(a)) Some(this.apply(a)) else None
}

val s = "1000"
val IntString(i) = s

完美运行但是

implicit object IntString extends PartialFunction[String, Int] {
  def isDefinedAt(x: String) = Try(x.toInt).isSuccess
  def apply(v1: String) = v1.toInt

  def unapply(a:String):Option[Int] = if(this.isDefinedAt(a)) Some(this.apply(a)) else None
}

val s = "1000"
val IntString(i) = s

apply方法中给出了一个Whosebug。我希望能够隐含对象,这样我就可以做类似

的事情
def parse[A,B](a:A)(implicit ev:PartialFunction[A,B]) = ev(a)

除了显式 apply/unapply。

apply 都出错了,特别是 v1.toIntjava.lang.String 没有 toInt 方法。它由 StringLike 隐式提供。但是 Int 有一个 toInt 方法,并且您提供了从 String => Int.

的隐式转换

编译器发现您想在 String 上调用 toInt。编译器知道 Int 有一个 toInt 方法,而不是从 StringLike 中选择丰富的方法,而你在范围内提供了一个隐式的 String => Int,所以它使用那个.但是再次使用您的转换调用 apply,它会无限重复该过程。

一个简单的解决方案是使用实际类型 class,而不是 PartialFunction:

trait Conv[A, B] {
    def isDefinedAt(x: A): Boolean
    def apply(v1: A): B
    def unapply(a: A): Option[B]
}

implicit object IntString extends Conv[String, Int] {

  def isDefinedAt(x: String) = Try(x.toInt).isSuccess

  def apply(v1: String): Int = v1.toInt

  def unapply(a: String): Option[Int] =
    if(this.isDefinedAt(a)) Some(this.apply(a)) else None
}

scala> val IntString(i) = s
i: Int = 1000

然后您将 parse 更改为:

def parse[A, B](a: A)(implicit ev: Conv[A,B]) = ev(a)