json - 具有自定义键类型的 Data.Map.Strict.Map 的 Aeson 编码导致数组数组而不是对象

标签 json haskell aeson

当我使用自定义类型作为键时,我无法让 Aeson 吐出对象。让我演示一下:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

import Data.Aeson

import qualified Data.Map.Strict as M
import qualified Data.ByteString.Lazy.Char8 as B

import GHC.Generics

data LOL = A | B | C deriving (Eq, Ord, Generic, ToJSONKey, ToJSON)
main = do
    B.putStrLn $ encode $ M.fromList [(A,"b")]
    B.putStrLn $ encode $ M.fromList [("A","b")]

在一种情况下,我得到一个数组数组,而在另一种情况下,它是一个常规对象:

$ ./tojsonkey 
[["A","b"]]
{"A":"b"}

有什么想法吗?

最佳答案

看看the docs for ToJSONKey .基本上,toJSONKey::ToJSONKeyFunction a 方法处理两种情况:

  1. 当您可以将 key 直接转换为类似文本的内容时
  2. 当你能做的最好的事情就是将 key 转换成一些通用的 JSON

对于其中的第一个,aeson 将使用适当的 JSON 对象。对于后者,它会退回到嵌套数组。

那么为什么在您的案例中选择选项二?因为您正在派生 ToJSONKey 并且默认实现选择第二个更通用的选项。您可以通过手动实现 ToJSONKey LOL 来解决此问题:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

import Data.Aeson
import Data.Aeson.Types

import qualified Data.Text as T
import qualified Data.Map.Strict as M
import qualified Data.ByteString.Lazy.Char8 as B

import GHC.Generics

data LOL = A | B | C deriving (Eq, Ord, Show, Generic, ToJSON)
instance ToJSONKey LOL where
  toJSONKey = toJSONKeyText (T.pack . show)

main = do
    B.putStrLn $ encode $ M.fromList [(A,"b")]
    B.putStrLn $ encode $ M.fromList [("A","b")]

那应该给你

$ ./tojsonkey 
{"A":"b"}
{"A":"b"}

关于json - 具有自定义键类型的 Data.Map.Strict.Map 的 Aeson 编码导致数组数组而不是对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55079309/

相关文章:

json - 如何使用 Haskell Lens 重写 JSON 结构中的任意嵌套字段?

javascript - 用于从 url 中提取不带扩展名的文件名的正则表达式

javascript - 按字母顺序组织 JSON 数据

haskell - 如何从Haskell链接到C#(即托管)DLL?

function - IO对象Haskell的问题

parsing - 如何在使用 Data.Aeson 解析 JSON 时正确出错

javascript - 使用 handlebars.js 显示 JSON 数据

c# - 带有 System.Text.Json 的可选属性的自定义 JSON 序列化程序

haskell - 有 ghci 缩写命令列表吗?

haskell - 如何在不声明单个类型的情况下使用 Aeson 解析 JSON