我正在编写一个类型类来转换类型,我注意到隐式对象上的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。
答案 0 :(得分:3)
apply
出现问题,特别是v1.toInt
。 java.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)