2017-05-31 108 views
5

(斯卡拉2.11.8)斯卡拉類型類的隱式解析

考慮下面的代碼:

object ScalaTest extends App { 
    class Wrapper { 
    import Wrapper._ 

    def init(): Unit = { 
     // "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]" 
     printWithTC(123) 

     // Compiles 
     printWithTC(123)(IntTC) 

     // Compiles again! 
     printWithTC(132) 
    } 
    } 

    object Wrapper { 
    trait TC[A] { 
     def text(a: A): String 
    } 

    implicit object IntTC extends TC[Int] { 
     override def text(a: Int) = s"int($a)" 
    } 

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = { 
     println(tc.text(a)) 
    } 
    } 

    (new Wrapper).init() 
} 

我有一堆關於這段代碼的問題:

  1. 爲什麼沒有按」 t IntTC首先得到解決?
  2. 爲什麼使用一次後編譯? (如果您註釋掉第一個調用,代碼有效)
  3. 應該將typeclass implicits放在哪裏才能正確解析?
+3

我不知道發生了什麼,但只是注意到,如果您將對象移到課前,代碼也會編譯。 – Dima

回答

3

使用帶明確返回類型的val。見https://github.com/scala/bug/issues/801https://github.com/scala/bug/issues/8697(等等)。
隱式對象具有與推斷返回類型的隱式vals和defs相同的問題。至於你的第二個問題:當明確使用IntTC時,你強制編譯器對它進行類型檢查,所以在該點之後,它的類型是已知的並且可以通過隱式搜索找到。

class Wrapper { 
    import Wrapper._ 

    def init(): Unit = { 
    // Compiles 
    printWithTC(123) 

    // Compiles 
    printWithTC(123)(IntTC) 

    // Compiles 
    printWithTC(132) 
    } 
} 

object Wrapper { 
    trait TC[A] { 
    def text(a: A): String 
    } 

    implicit val IntTC: TC[Int] = new TC[Int] { 
    override def text(a: Int) = s"int($a)" 
    } 

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = { 
    println(tc.text(a)) 
    } 
} 

如果你真的想你隱懶洋洋地像一個對象進行評估,你可以使用一個implicit lazy val有一個明確的類型。

0

在使用它之前定義隱式。

object Wrapper { 
    trait TC[A] { 
    def text(a: A): String 
    } 

    implicit object IntTC extends TC[Int] { 
    override def text(a: Int) = s"int($a)" 
    } 

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = { 
    println(tc.text(a)) 
    } 
} 

class Wrapper { 
    import Wrapper._ 

    def init(): Unit = { 
    // "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]" 

    printWithTC(123) 

    // Compiles 
    printWithTC(123)(IntTC) 

    // Compiles again! 
    printWithTC(132) 
    } 
} 

(new Wrapper).init() 
+0

我們不是將整個對象內容作爲類內的第一行導入到類作用域中嗎?另外,在類之後定義伴隨對象是很常見的(例如,http://docs.scala-lang.org/tutorials/tour/singleton-objects.html),所以這是相當不方便的解決方法 –