【问题标题】:How does Scala use explicit types when resolving implicits?Scala 在解析隐式时如何使用显式类型?
【发布时间】:2015-12-03 00:20:33
【问题描述】:

我有以下代码,它使用 spray-json 通过parseJson 方法将一些 JSON 反序列化为案例类。

取决于隐式 JsonFormat[MyCaseClass] 的定义位置(内联或从伴随对象导入),以及定义时是否提供了显式类型,代码可能无法编译。

我不明白为什么从伴随对象中导入隐式需要它在定义时具有显式类型,但如果我把它内联,就不是这样了吗?

有趣的是,IntelliJ 在所有情况下都能正确定位隐式参数(通过 cmd-shift-p)。

我使用的是 Scala 2.11.7。

Broken Code - 从伴随对象导入通配符,推断类型:

import SampleApp._
import spray.json._

class SampleApp {
  import MyJsonProtocol._
  val inputJson = """{"children":["a", "b", "c"]}"""
  println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}")
}

object SampleApp {
  case class MyCaseClass(children: List[String])

  object MyJsonProtocol extends DefaultJsonProtocol {
    implicit val myCaseClassSchemaFormat = jsonFormat1(MyCaseClass)
  }
}

结果:

Cannot find JsonReader or JsonFormat type class for SampleAppObject.MyCaseClass

请注意,显式导入 myCaseClassSchemaFormat 隐式也会发生同样的事情。

工作代码 #1 - 从伴随对象导入通配符,显式类型:

在伴生对象中向 JsonFormat 添加显式类型会导致代码编译:

import SampleApp._
import spray.json._

class SampleApp {
  import MyJsonProtocol._
  val inputJson = """{"children":["a", "b", "c"]}"""
  println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}")
}

object SampleApp {
  case class MyCaseClass(children: List[String])

  object MyJsonProtocol extends DefaultJsonProtocol {
    //Explicit type added here now
    implicit val myCaseClassSchemaFormat: JsonFormat[MyCaseClass] = jsonFormat1(MyCaseClass)
  }
}

工作代码 #2 - 隐式内联,推断类型:

但是,将隐式参数放在使用它们的位置,没有显式类型,也可以!

import SampleApp._
import spray.json._

class SampleApp {
  import DefaultJsonProtocol._

  //Now in-line custom JsonFormat rather than imported
  implicit val myCaseClassSchemaFormat = jsonFormat1(MyCaseClass)

  val inputJson = """{"children":["a", "b", "c"]}"""
  println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}")
}

object SampleApp {
  case class MyCaseClass(children: List[String])
}

【问题讨论】:

  • 这是“当我这样做时很痛”的问题之一,其中最好的答案几乎肯定是“好吧,不要那样做”。以我的经验,缺少类型注释的隐式值是 Scala 中最常见的混淆、奇怪的跨版本行为差异等来源之一。
  • 嗨,Travis - 确实,这是一个可以解决的有趣错误,但我想下次类型注释将是我解决类似问题的第一个停靠点!不确定这是否算作 Scala 错误,但可能会将某些内容放入邮件列表/查看提出问题以防万一。
  • 编译器会吐出一条错误消息,说“隐式方法在此处不适用,因为它位于应用程序点之后,并且缺少显式结果类型”,因此至少该错误易于诊断和修复: )
  • 呵呵,您是否使用以下任何代码示例收到类似的错误消息?我只收到粘贴的错误,Cannot find JsonReader or JsonFormat type class for SampleAppObject.MyCaseClass,但你的会更有用。

标签: scala implicit spray spray-json


【解决方案1】:

在搜索 Huw 在他的评论中提到的错误消息后,我能够找到 2010 年的这个 StackOverflow 问题:Why does this explicit call of a Scala method allow it to be implicitly resolved?

这让我想到了 2008 年创建并于 2011 年关闭的 Scala 问题:https://issues.scala-lang.org/browse/SI-801('需要显式结果类型才能进行隐式转换?')

马丁说:

我已经实现了一个稍微宽松的规则:没有显式结果类型的隐式转换仅在其自己定义的文本中可见。这样,我们就避免了循环引用错误。我现在关闭,看看它是如何工作的。如果我们仍然有问题,我们可能会回到这个问题。

这成立 - 如果我重新排序中断代码以便声明伴随对象首先,然后代码编译。(这还是有点奇怪!)

(我怀疑我没有看到 'implicit method is not applicable here' 消息,因为我有一个隐式值而不是转换 - 尽管我在这里假设根本原因是同上)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-24
    • 1970-01-01
    • 2019-06-30
    • 2012-08-25
    • 2017-01-30
    • 2016-07-12
    • 1970-01-01
    • 2023-03-05
    相关资源
    最近更新 更多