解析隐式时,Scala如何使用显式类型? [英] How does Scala use explicit types when resolving implicits?
问题描述
我有以下代码,该代码使用spray-json通过parseJson
方法将某些JSON反序列化为case类.
I have the following code which uses spray-json to deserialise some JSON into a case class, via the parseJson
method.
取决于隐式JsonFormat [MyCaseClass]的定义位置(嵌入式或从同伴对象导入)以及定义时是否提供显式类型,代码可能无法编译.
Depending on where the implicit JsonFormat[MyCaseClass] is defined (in-line or imported from companion object), and whether there is an explicit type provided when it is defined, the code may not compile.
我不明白为什么从同伴对象导入隐式对象时要求它在定义时必须具有显式类型,但是如果我将其内联,则不是这种情况吗?
I don't understand why importing the implicit from the companion object requires it to have an explicit type when it is defined, but if I put it inline, this is not the case?
有趣的是,在所有情况下,IntelliJ都可以通过cmd-shift-p正确地找到隐式参数.
Interestingly, IntelliJ correctly locates the implicit parameters (via cmd-shift-p) in all cases.
我正在使用Scala 2.11.7.
I'm using Scala 2.11.7.
破损代码-从伴随对象导入通配符,推断类型:
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
隐式也会发生同样的事情.
Note that the same thing happens with an explicit import of the myCaseClassSchemaFormat
implicit.
工作代码#1-从伴随对象导入通配符,显式类型:
在伴随对象中的JsonFormat中添加显式类型会导致代码编译:
Adding an explicit type to the JsonFormat in the companion object causes the code to compile:
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-隐式内联,推断类型:
但是,将隐式参数放在使用它们的位置(不显式类型)也行得通!
However, putting the implicit parameters in-line where they are used, without the explicit type, also works!
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])
}
推荐答案
在搜索到Huw在其注释中提到的错误消息后,我能够找到2010年以下的StackOverflow问题:
After searching for the error message Huw mentioned in his comment, I was able to find this StackOverflow question from 2010: 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 (需要隐式转换的显式结果类型吗?")
This led me to this Scala issue created in 2008, and closed in 2011: https://issues.scala-lang.org/browse/SI-801 ('require explicit result type for implicit conversions?')
马丁说:
我实现了一个更宽松的规则:没有显式结果类型的隐式转换仅在其自身定义之后的文本中可见.这样,我们避免了循环参考误差.我现在关闭,看看它是如何工作的.如果仍然有问题,我们会回头再来.
I have implemented a slightly more permissive rule: An implicit conversion without explicit result type is visible only in the text following its own definition. That way, we avoid the cyclic reference errors. I close for now, to see how this works. If we still have issues we migth come back to this.
这成立了-如果我重新排序中断代码,以便首先将伴随对象声明为 ,然后编译代码.(仍然有点怪异!)
This holds - if I re-order the breaking code so that the companion object is declared first, then the code compiles. (It's still a little weird!)
(我怀疑我看不到'隐式方法在这里不适用'消息,因为我具有隐式值而不是转换-尽管我在这里假设根本原因是与上述相同).
(I suspect I don't see the 'implicit method is not applicable here' message because I have an implicit value rather than a conversion - though I'm assuming here that the root cause is the same as the above).
这篇关于解析隐式时,Scala如何使用显式类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!