2015-09-04 53 views
1

我正在写一个类型类型之间转换类型,我注意到一些不寻常的方法隐式对象上的不正常。具体scala StackOverflow上隐式对象不适用

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。

回答

3

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

编译器发现你想在String上调用toInt。编译器知道Int有一个toInt方法,而您在范围内提供了一个隐含的String => Int,所以它使用它,而不是从StringLike中选择丰富的方法。但是使用你的转换再次调用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) 
+0

谢谢!这是对发生的事情的一个非常清楚的解释。我以为有某种意想不到的暗示技巧在继续,但我不确定是什么。我实际上想继续扩展'PartialFunction'(我的实际实现有一个扩展它的类型类),这样我就可以对'orElse'和'和Then'做一些事情,但根据你的回答,我把'v1.toInt'改为'Integer.parseInt(v1)',它工作。 –