2016-05-30 44 views
1

有類型如何將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

回答

3

這樣做的另一種方法可能是定義一個函數,接受名稱和電子郵件並返回您的Named構造:

userDecoder : Decoder User 
userDecoder = 
    let 
    named = 
     object2 
     (\n e -> Named { name = n, email = e }) 
     ("name" := string) 
     ("email" := string) 
    in 
    oneOf [ null Anonymous, named ] 
2

由於您的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