2014-08-29 95 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

相關問題