2014-08-29 70 views

回答

1

它可能是协变的,特别是当您将Reads[A]视为JsValue => A的更丰富形式时。

但是...... 隐含性

Reads[A]不只是是从JsValue转换为A一个方式,方式。

所以,如果我们有

sealed trait Foo 
case class Bar(a: Int) 
case class Baz(b: Int) 

如果你定义一个Reads[Bar],你也(协方差)有Reads[Foo]

这可能有点奇怪。

object Foo { 
    implicit reads: Reads[Foo] = 
    implicitly[Reads[Bar]].orElse[implicitly[Reads[Baz]]] 
} 
object Bar { 
    implicit reads = Json.reads[Bar] // {"a":0} 
} 
object Baz { 
    implicit reads = Json.reads[Baz] // {"b":0} 

    def blah(jsValue: JsValue): Foo = jsValue.as[Foo] 
} 
object Main { 
    def blah(jsValue: JsValue): Foo = jsValue.as[Foo] 
} 

什么Baz.blahMain.blah是怎么回事?前者使用Baz.reads,后者使用Foo.reads,因为(复杂)隐式解析顺序。

这是一个边缘案例,我仍然认为你可以为协变做出很好的论证,但它确实显示了“东西可能解析JSON到Foo”和“可以解析JSON到所有可能的Foo“。

+0

谢谢,暗示就是这样,就像我想的那样。你能评论一下这个要点吗?如果你写一个'读取[Child] .map(x => x)'或'读取[Child] .as [Reads [Parent]]',你的意见是什么? – phadej 2015-10-05 07:49:23

+0

@phadej,你的意思是'.asInstanceOf'?无论如何,我认为扩展类型并不是什么坏事。唯一的问题是如果它是自动完成的。 – 2015-10-05 13:32:18

8

假设Reads是协变的。我有一个简单的类型层次:

sealed trait Foo { def name: String } 
case class Bar(name: String, i: Int) extends Foo 
case class Baz(name: String, c: Char) extends Foo 

而对于case类的一个实例Reads

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

implicit val readsBar: Reads[Bar] = (
    (__ \ 'name).read[String] and (__ \ 'i).read[Int] 
)(Bar.apply _) 

Bar <: Foo,所以Reads[Bar] <: Reads[Foo],这是没有意义的,我没有说什么关于如何解码Baz,所以我显然实际上没有Reads[Foo]

更好的问题可能是为什么Reads不是逆变。

+0

但是,如果我有非隐式的'readsBar:Reads [Bar]'和'readsBaz:Reads [Baz]':那么'readsFoo = readsBar或Else readsBaz'不起作用。但是'readsFoo = readsBar.map(x => x)或者elsese readsBaz.map(x => x)'是可以的。在这里我看到了协变映射。 – phadej 2014-08-29 18:24:04

+0

这仍然困扰我,我写了一个小小的要点,希望澄清这个问题:https://gist.github.com/phadej/c60912802dc494c3212b – phadej 2014-10-08 17:59:18

+0

我不这样解释就够了。你仍然有一种将JSON转换为'Foo'的方式,所以'Reads [Bar]'*'是* Reads [Foo]'。 – 2015-10-04 01:49:00

相关问题