如何将JSON解码为由数据构造函数构建的记录?

问题描述:

有类型如何将JSON解码为由数据构造函数构建的记录?

type User 
    = Anonymous 
    | Named {name : String, email : String} 

Json.Decode.object2不适合在这里,因为它的第一个参数类型是(a -> b -> c)Named具有{ email : String, name : String } -> User型。

如何解码为用户?

+2

你可以提供既代表一个匿名的,并命名为用户的JSON的例子吗? –

+0

'[{“user”:null},{“user”:{“name”:“John Doe”,“email”:“[email protected]”}}]' – ztsu

这样做的另一种方法可能是定义一个函数,接受名称和电子邮件并返回您的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