如何将JSON解码为由数据构造函数构建的记录?
问题描述:
type User
= Anonymous
| Named {name : String, email : String}
Json.Decode.object2
不适合在这里,因为它的第一个参数类型是(a -> b -> c)
但Named
具有{ email : String, name : String } -> User
型。
如何解码为用户?
答
这样做的另一种方法可能是定义一个函数,接受名称和电子邮件并返回您的Named
构造:
userDecoder : Decoder User
userDecoder =
let
named =
object2
(\n e -> Named { name = n, email = e })
("name" := string)
("email" := string)
in
oneOf [ null Anonymous, named ]
答
由于您的Named
构造函数将一条记录作为参数,因此为名称和电子邮件记录创建一个类型别名可能会稍微清晰一些。
type alias NamedUserInfo =
{ name : String
, email : String
}
然后,您可以重新定义User
使用别名:
type User
= Anonymous
| Named NamedUserInfo
虽然上面是不是绝对必要的,我发现混淆记录类型在许多方面的道路证明是有用的。这是因为它给了我们一个构造NamedUserInfo
,让我们清楚地定义一个解码器是有用的:
import Json.Decode exposing (..)
namedUserInfoDecoder : Decoder NamedUserInfo
namedUserInfoDecoder =
object2
NamedUserInfo
("name" := string)
("email" := string)
最后,您的用户解码器可以构建这样的:
userDecoder : Decoder User
userDecoder =
oneOf
[ null Anonymous
, object1 Named namedUserInfoDecoder
]
你可以运行你的榜样通过这样的快速测试:
exampleJson =
"""
[{"user":null}, {"user": {"name": "John Doe", "email": "[email protected]"}}]
"""
main =
text <| toString <| decodeString (list ("user" := userDecoder)) exampleJson
-- Ouputs:
-- Ok ([Anonymous,Named { name = "John Doe", email = "[email protected]" }])
+0
谢谢您的完整解答。我猜想这是不可能的。我将重新考虑我的模型,并尝试不使用数据构造函数的记录。 – ztsu
你可以提供既代表一个匿名的,并命名为用户的JSON的例子吗? –
'[{“user”:null},{“user”:{“name”:“John Doe”,“email”:“[email protected]”}}]' – ztsu