2015-09-04 68 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)',它工作。 –