我有一个参数化的case类CaseClass[T](name: String, t: T),我希望使用play (2.5)进行序列化/反序列化。
当然,如果我没有T类型的等效值,我就不能这样做,所以我定义
object CaseClass {
implicit def reads[T: Reads] = Json.reads[CaseClass[T]]
}但是,我得到了以下编译器错误:
overloaded method value apply with alternatives:
[B](f: B => (String, T))(implicit fu: play.api.libs.functional.ContravariantFunctor[play.api.libs.json.Reads])play.api.libs.json.Reads[B] <and>
[B](f: (String, T) => B)(implicit fu: play.api.libs.functional.Functor[play.api.libs.json.Reads])play.api.libs.json.Reads[B]
cannot be applied to ((String, Nothing) => CaseClass[Nothing])如果我试图对Json.writes宏执行相同的操作,则会得到错误
type mismatch;
found : CaseClass[Nothing] => (String, Nothing)
required: CaseClass[T] => (String, T)最令人惊讶的是,当我使用Json.format宏时,两种错误都不会发生。
我知道我有不同的解决方案来解决这个问题(使用Json.format,手工编写我的(反)序列化程序,.),但是我很好奇为什么这里会出现这种情况。
发布于 2017-03-29 19:39:38
这要么是Json.reads宏、类型推断的限制,要么两者兼而有之。类型推断至少与此有一点关系,因为您可以在错误消息中看到一些被推断为Nothing的内容。
如果使用编译器标志-Ymacro-debug-lite,则可以看到宏生成的AST。
implicit def reads[T](implicit r: Reads[T]): Reads[CaseClass[T]] =
Json.reads[CaseClass[T]]翻译为:
_root_.play.api.libs.json.JsPath.$bslash("name").read(json.this.Reads.StringReads)
.and(_root_.play.api.libs.json.JsPath.$bslash("t").read(r))
.apply((CaseClass.apply: (() => <empty>)))清理干净后,看上去像是:
implicit def reads[T](implicit w: Reads[T]): Reads[CaseClass[T]] = (
(JsPath \ "name").read(Reads.StringReads) and
(JsPath \ "t" ).read(r)
)(CaseClass.apply _)不幸的是,它没有编译,因为没有提供CaseClass.apply的类型参数,并将其推断为Nothing。手动将T添加到apply解决了这个问题,但是宏可能不知道CaseClass[T]中的T很重要。
为了更详细地解决类型推断问题,使用Reads组合器,我们调用FunctionalBuilder.CanBuild2#apply,它需要一个(A1, A2) => B。但编译器无法正确推断A2。
对于Writes,有一个类似的问题,我们需要一个B => (A1, A2),但是编译器无法正确推断B或A2 (分别是CaseClass[T]和T )。
Format需要上述两个函数,编译器能够推理出A2必须是T。
https://stackoverflow.com/questions/43088507
复制相似问题