【问题标题】:Scala typeclasses implicit resolutionScala 类型类隐式解析
【发布时间】:2017-05-31 21:04:21
【问题描述】:

(斯卡拉 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. 为什么IntTC 不首先得到解决?
  2. 为什么使用一次就可以编译? (如果您注释掉第一次调用,代码可以工作)
  3. 类型类隐式应该放在哪里才能正确解析?

【问题讨论】:

  • 我不知道发生了什么,但只是注意到,如果你将对象移动到课堂之前,代码也会编译。

标签: scala typeclass implicit


【解决方案1】:

使用具有显式返回类型的val。请参阅 https://github.com/scala/bug/issues/801https://github.com/scala/bug/issues/8697(以及其他)。
隐式对象与具有推断返回类型的隐式 val 和 def 具有相同的问题。至于您的第二个问题:当显式使用 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

【讨论】:

    【解决方案2】:

    在使用前定义隐式。

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

    【讨论】:

    猜你喜欢
    • 2012-08-25
    • 1970-01-01
    • 2017-01-30
    • 2019-06-30
    • 2020-08-05
    • 2015-12-03
    • 2016-07-12
    • 2021-01-07
    • 2018-11-21
    相关资源
    最近更新 更多