scala StackOverflow对隐式对象的应用

时间:2015-09-04 15:11:13

标签: scala typeclass implicit

我正在编写一个类型类来转换类型,我注意到隐式对象上的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方法给出StackOverflow。我希望能够让对象隐含,所以我可以做类似

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

除了明确的apply / unapply。

1 个答案:

答案 0 :(得分:3)

apply出现问题,特别是v1.toIntjava.lang.String没有toInt方法。它由StringLike隐式提供。但是Int 有一个toInt方法,并且您提供了String => Int的隐式转换。

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

一个简单的解决方案是使用实际的类型类,而不是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)