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

问题描述 投票:1回答:1

当我使用自定义类型作为键时,我无法让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"}

有任何想法吗?

json haskell aeson
1个回答
1
投票

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

  1. 当你可以直接把钥匙转成像文字一样的东西
  2. 当你能做的最好的事情是把钥匙变成一些普通的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"}
© www.soinside.com 2019 - 2024. All rights reserved.