What is this “and” in ScalaJsonCombinator (when defining a Writes)?

梦想与她 提交于 2019-12-12 03:23:58

问题


I've been using this json combinator for several basic / standard cases without really understanding how it works. All was fine.

Now I want to get myself prepared for whatever advanced cases might come; I need to understand the code.

Ref.: https://www.playframework.com/documentation/2.3.x/ScalaJsonCombinators

I think I can understand the Reads:

implicit val locationReads: Reads[Location] = (
  (JsPath \ "lat").read[Double] and
  (JsPath \ "long").read[Double]
)(Location.apply _)

It creates a Reads that:

  1. First -- when given a JsValue (through its "reads" method) -- it pulls the "lat", followed by the "long". Out of those two it creates a tuple (Double, Double). -- https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.json.Reads

  2. That tuple is then assigned to the partial function of that Reads..., which in this case is whatever returned by "Location.apply _". I tried it in repl:

...

scala> val yowMan = Location.apply _
yowMan: (Double, Double) => Location = <function2>

scala> yowMan(1, 2)
res14: Location = Location(1.0,2.0)

That partial function takes the a tuple of (Double, Double) as input. So..., the outcome of step 1 is channeled to step 2, and we get an instance of Location as the return of "reads".

Now for the Writes:

implicit val locationWrites: Writes[Location] = (
  (JsPath \ "lat").write[Double] and
  (JsPath \ "long").write[Double]
)(unlift(Location.unapply))

First the "unapply". I tried in repl:

scala> val heyDude = Location.unapply
<console>:16: error: missing arguments for method unapply in object Location;
follow this method with `_' if you want to treat it as a partially applied function
   val heyDude = Location.unapply

Oops, ok, I followed the instruction:

scala> val heyDude = Location.unapply _
heyDude: Location => Option[(Double, Double)] = <function1>

Ok, so we get a partial function that transforms an instance of Location to an (optional) tuple of (Double, Double).

Next, the "unlift":

scala> val hohoho = unlift(heyDude)
hohoho: Location => (Double, Double) = <function1>

scala> val loc = Location(1, 2)
loc: Location = Location(1.0,2.0)

scala> hohoho(loc)
res16: (Double, Double) = (1.0,2.0)

Ok, so... unlift simply throws away the "Option", and takes us directly to the tuple.

Ok... so... I guess... this "writes" of the Writes... *) when given an instance of Location, it will:

  1. Pass that object through that partial function produced by unlift(Location.unapply).

  2. The tuple (Double, Double) returned by that partial function is then channeled to whatever is produced by this:

    (JsPath \ "lat").write[Double] and (JsPath \ "long").write[Double]

What exactly is that "whatever"? Following the API doc of JsPath, I think it is OWrites: https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.json.OWrites

But... I can't see there's a method named "and" in OWrites. Where is this "and" declared? And what does it do? Is it: "oWrites1 and oWrites2" produces "oWrites3"? And this "oWrites3" is a special type of OWrites that takes tuple as input? ... If that's the case... the tuple doesn't have information about the name of the property in the case class ("lat" and "long"). How does it know that the produced json string should be {"lat": 1, "long": 2} then?

Sorry for the train of questions. Please help me obtaining a clear understanding of this. Thanks!

*) https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.json.Writes


UPDATES:

  • Adding related question: Syntax and meaning of a Scala/Play! code sample

回答1:


When in doubt, decompile it. This showed that there is an implicit toFunctionalBuilderOps, which then you can see in FunctionalBuilderOps that there is your and method



来源:https://stackoverflow.com/questions/28329367/what-is-this-and-in-scalajsoncombinator-when-defining-a-writes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!