我有一些来自Firebase的JSON
{
"type": "added",
"doc": {
"id": "asda98j1234jknkj3n",
"data": {
"title": "Foo",
"subtitle": "Baz"
}
}
}
类型可以是"added"
,"modified"
或"removed"
中的一种。 Doc
包含一个id
和一个data
字段。 data
字段可以是任何形状,我能够对其进行正确解码。
我想使用联合类型来表示这些值,
type alias Doc data =
(String, data)
type DocChange doc
= Added doc
| Modified doc
| Removed doc
这里的Doc
类型别名表示上面JSON中doc
字段中包含的值。 DocChange
代表整个事情。如果类型为"added"
,则JSON必须解码为Added doc
,依此类推。我不明白如何解码联合类型。
我认为andThen
中的Json.Decode
函数看起来像我需要的,但是我无法正确使用它。
答案 0 :(得分:4)
首先,您似乎想将doc
的{{1}}参数限制为DocChange
,所以您应该这样定义它:
Doc
否则,您将不得不在函数类型注解中重复指定type DocChange data
= Added (Doc data)
| Modified (Doc data)
| Removed (Doc data)
,这很快会令人讨厌,并且嵌套的次数越多越糟。无论如何,我都会继续使用您定义的类型:
DocChange (Doc data)
这里的技巧是先解码decodeDocData : Decoder DocData
decodeDocData =
map2 DocData
(field "title" string)
(field "subtitle" string)
decodeDoc : Decoder data -> Decoder (Doc data)
decodeDoc dataDecoder =
map2 Tuple.pair
(field "id" string)
(field "data" dataDecoder)
decodeDocChange : Decoder data -> Decoder (DocChange (Doc data))
decodeDocChange dataDecoder =
field "type" string
|> andThen
(\typ ->
case typ of
"added" ->
map Added
(field "doc" (decodeDoc dataDecoder))
"modified" ->
map Modified
(field "doc" (decodeDoc dataDecoder))
"removed" ->
map Removed
(field "doc" (decodeDoc dataDecoder))
_ ->
fail ("Unknown DocChange type: " ++ typ)
)
,然后使用"type"
打开它并选择适当的解码器。在这种情况下,“类型”上的形状是相同的,但可能并非完全相同,并且该图案也提供了处理各种形状的灵活性。如果您完全确定它们不会发生分歧,可以简化为只选择构造函数并使其余解码保持公共状态。