2015-08-29 18 views

回答

19

通常你知道编码器总是会产生一个JSON对象(而不是任意的JSON值)。在类型系统中跟踪这个事实使得可以使用这样的编码器的输出来工作,而不用跳过通常是必需的环。

例如,假设我们有一个简单的类:

class Foo(val name: String, val age: Long) 

我们写一个Writes情况是这样的:

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

implicit val fooWrites: Writes[Foo] = (
    (__ \ 'name).write[String] and (__ \ 'age).write[Long] 
)(foo => (foo.name, foo.age)) 

现在我们可以写:

scala> val json = fooWrites.writes(new Foo("McBar", 101)) 
json: play.api.libs.json.JsValue = {"name":"McBar","age":101} 

现在假设我们想要得到一个字段名称列表,无论出于何种原因。我们必须写这样的事:

scala> json.as[JsObject].keys 
res0: scala.collection.Set[String] = Set(name, age) 

取而代之的是:

scala> json.keys 
<console>:17: error: value keys is not a member of play.api.libs.json.JsValue 
       json.keys 
       ^

但当然我们知道json将永远是一个JsObject。问题是编译器没有。 OWrites解决了这个问题。

implicit val fooWrites: OWrites[Foo] = (
    (__ \ 'name).write[String] and (__ \ 'age).write[Long] 
)(foo => (foo.name, foo.age)) 

然后:

scala> val json = fooWrites.writes(new Foo("McBar", 101)) 
json: play.api.libs.json.JsObject = {"name":"McBar","age":101} 

scala> json.keys 
res1: scala.collection.Set[String] = Set(name, age) 

writesOWrites输出静态类型为JsObject,所以我们可以使用.keys没有不安全as[JsObject]演员。

(作为一个方面说明,我制作方法的返回类型的子类更具体的not personally a fan,我已经采取了a slightly different approachcirce解决这个问题。)

+0

所以,你说的是,如果我知道某个东西是Json对象(而不是Json数组)比实现一个OWrites而不是一个Writes更好,对吧?关于“不是个人粉丝”中的链接,我无法在任何地方找到“更具体的返回类型”,所以我无法得到这个想法。你能解释一下你连接的问题吗?感谢OWrites的解释:) – vicaba

+1

如果您的用例需要它,则更为可取。我不知道'OWriter'是否给你比普通的'Writer'更多/不同的功能,除了你在编译时知道它是一个JsObject。我认为@Travis所说的“更具体的返回类型”是指'OWrites [T]扩展Writes [T]'其中'Writest [T]''def写入(in:T):JsValue',而同样的方法在'OWrites [T]'是'def writes(in:T):JsObject',其中'JsObject'是'JsValue'的子类。 – goral

+0

@goral是的,我在Writes和OWrites的例子中看到了这个想法,但是我不明白的是这里发生了什么:http:// stackoverflow。com/questions/31080332/why-is-upcasting-necessary-in-this-scala-code#comment50187425_31080332 – vicaba

相关问题