为啥 Json.writes[T] 需要一个 `apply` 方法?

Posted

技术标签:

【中文标题】为啥 Json.writes[T] 需要一个 `apply` 方法?【英文标题】:Why does Json.writes[T] require an `apply` method?为什么 Json.writes[T] 需要一个 `apply` 方法? 【发布时间】:2015-11-10 05:23:14 【问题描述】:

我有一些扩展此类的案例类:

class CitySuggestion(val name: String, val locationId: String, val locationKind: String)

我想使用 Json.writes[CitySuggestion] 作为这个类的 JSON 编写器,所以我在它的伴生对象中定义了一个 unapply 方法:

object CitySuggestion 
  def unapply(cs: CitySuggestion): Option[(String, String, String)] =
    Some((cs.name, cs.locationId, cs.locationKind))

我认为这样就足够了,但编译器现在也要求提供 apply 方法:

未找到应用函数 [错误] 隐式惰性 val citySuggestionWrites = Json.writes[CitySuggestion]

为什么需要一个 apply 方法?我不想反序列化 JSON,我必须添加逻辑来确定它应该反序列化到哪个子类的实例。

【问题讨论】:

如果您将CitySuggestion 设为案例类,则无需手动定义任何一种方法,尽管您的用例可能会阻止这种情况。 @greggory.hz 谢谢,我不能让它成为一个案例类,因为我正在扩展那个类 【参考方案1】:

发生这种情况是因为 Play Json 的 writesreads 宏共享一个 common implementation. 在此实现中,为 Json.writes[A] 提供的类型 A 会检查其 apply 方法,该方法又用于生成 apply对于Writes 实例。

作为使用“写入”宏的替代方法,您可以创建自己的 Write[CitySuggestion],如下所示:

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val citySuggestionWrites: Writes[CitySuggestion] = (
  (JsPath \ "name").write[String] and
  (JsPath \ "locationId").write[String] and
  (JsPath \ "locationKind").write[String]
)(unlift(CitySuggestion.unapply))

【讨论】:

以上是关于为啥 Json.writes[T] 需要一个 `apply` 方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个 t.test 的变体需要不同的编码? (右)

为啥重载的scala函数需要返回类型?

为啥在咖啡脚本的每个块的末尾都需要一个“未定义”?

为啥 HashSet<T> 没有实现 ICollection?

实现Runnable的多线程代码中,while(true)表示的啥含义?为啥没有while(t

为啥我们需要估计卡尔曼滤波器中的真实位置?