json - 如何将 JSON 值解压缩为标记的联合类型?
问题描述
我有一些来自 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
类型别名表示doc
上面 JSON 中的字段中包含的值。DocChange
代表整个事物。如果类型是 say "added"
,那么 JSON 必须解码成Added doc
等等。我不明白如何解码联合类型。
我认为andThen
from 的功能Json.Decode
看起来像我需要的,但我无法正确使用它。
解决方案
首先,您似乎想将doc
参数限制DocChange
为 a 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"
,然后使用andThen
打开它并选择合适的解码器。在这种情况下,“类型”中的形状是相同的,但可能不是,这种模式也可以灵活地处理不同的形状。如果您绝对确定它们不会发散,则可以将其简化为仅选择构造函数并保持其余解码通用。
推荐阅读
- r - 为什么 ggplot2 的图例标签为“a”?
- google-cloud-storage - 我可以允许根据网站的公开请求呈现项目,但不能直接在浏览器中查看吗?
- python - 为什么 Netbeans 将 Python f-string 显示为错误?
- reactjs - React-Redux:状态变化不要调用 mapStateToProps
- reactjs - 模拟嵌套在路由器和 Provider 组件中的 this.props.dispatch
- python-3.x - 将年度时间序列转换为月度
- c++ - “如果引用专业化的上下文取决于模板参数”是什么意思?
- ruby-on-rails - 如何为非 Active Record 对象支持 Rails 可回收缓存键
- powerpivot - 计算人口月份
- django - 找不到 gunicorn.socket 的工作