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

How to decode JSON to record built by a data constructor?

有型

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

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

如何解码给用户?

由于您的 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": "j.doe@mailg.com"}}]
  """

main =
  text <| toString <| decodeString (list ("user" := userDecoder)) exampleJson

-- Ouputs:
-- Ok ([Anonymous,Named { name = "John Doe", email = "j.doe@mailg.com" }])

另一种方法是定义一个接受姓名和电子邮件的函数以及 returns 您的 Named 构造函数:

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