2017-05-31 101 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),所以这是相当不方便的解决方法 –