Play 的 JSON library 包括 Functor
和 Invariant Functor
:
我以前见过 Functor
:
trait Functor[M[_]] extends Variant[M] {
def fmap[A, B](m: M[A], f: A => B): M[B]
}
但是,从概念上讲,为什么有必要为
f1
提供 f2
和 InvariantFunctor
函数?trait InvariantFunctor[M[_]] extends Variant[M] {
def inmap[A, B](m: M[A], f1: A => B, f2: B => A): M[B]
}
最佳答案
在 this answer 中,我快速解释了为什么 Writes
不是仿函数——即,为什么如果我们有 Writes[A]
和函数 A => B
我们不能像使用 Writes[B]
一样创建 Reads
。
正如我在那个答案中所指出的, Writes
不是一个普通的(协变)仿函数,而是一个逆变仿函数,这意味着如果我们有一个 Writes[A]
和一个函数 B => A
,我们可以创建一个 Writes[B]
。Format
包含了 Reads
和 Writes
的功能,这意味着它既不是仿函数也不是逆变仿函数——但它是一个不变仿函数(而且它确实是唯一一个你会在上下文中遇到的具有不变仿函数实例的类型玩)。
要了解为什么会这样,假设我们有以下两种类型:
case class Foo(i: Int, s: String)
case class Bar(s: String, i: Int)
假设我们有一个
Format
的 Foo
实例:import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val fooFormat = Json.format[Foo]
但是无论出于何种原因,我们都无法以相同的方式为
Bar
创建一个——我们希望从 Foo
的那个派生它。仅仅知道如何从 Bar
创建 Foo
是不够的,反之亦然,但是如果我们可以双向使用,我们可以对 Format
使用不变仿函数:implicit val barFormat = fooFormat.inmap[Bar](
foo => Bar(foo.s, foo.i),
bar => Foo(bar.i, bar.s)
)
这是因为我们可以将
Format
视为一个双向管道,它允许我们放入 JsValue
并取出一些 A
,或者放入 A
并取出 JsValue
。如果我们想将双向管道 Format[A]
转换为双向管道 Format[B]
,我们需要两端的适配器(即 A => B
和 B => A
)。关于scala - Play JSON InvariantFunctor,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21990112/