简体   繁体   English

Scala类型类隐式解析

[英]Scala typeclasses implicit resolution

(Scala 2.11.8) (斯卡拉2.11.8)

Consider the following code: 请考虑以下代码:

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()
}

I have a bunch of questions regarding this piece of code: 关于这段代码,我有很多问题:

  1. Why doesn't IntTC get resolved in the first place? 为什么IntTCIntTC得到解决?
  2. Why it compiles after being used once? 为什么它在使用一次后编译? (if you comment out the first invocation, code works) (如果您注释掉第一次调用,代码可以正常工作)
  3. Where should typeclass implicits be placed to get resolved properly? 应该在哪里设置类型隐含以便正确解决?

Use a val with a explicit return type. 使用具有显式返回类型的val See https://github.com/scala/bug/issues/801 and https://github.com/scala/bug/issues/8697 (among others). 请参阅https://github.com/scala/bug/issues/801https://github.com/scala/bug/issues/8697 (以及其他内容)。
Implicit objects have the same issue as implicit vals and defs with inferred return types. 隐式对象与隐式val和defs具有相同的问题,具有推断的返回类型。 As for your second question: when IntTC is used explicitly you force the compiler to typecheck it, so after that point its type is known and can be found by implicit search. 至于你的第二个问题:当显式使用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))
  }
}

If you really want your implicit to be evaluated lazily like an object, you can use an implicit lazy val with an explicit type. 如果你真的希望像对象那样implicit lazy val地对你的隐式进行求值,你可以使用带有显式类型的implicit lazy val

Define the implicit before the use of it. 在使用之前定义隐式。

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM