You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Haskell Aeson为省略字段设置默认值失效问题

问题原因

你错误使用了FromJSON类型类中的omittedField方法——这个方法的作用是当整个类型的值被省略时(例如嵌套结构中某个可选的Person字段被省略)提供默认值,而非为单个缺失的字段填充默认值。因此当JSON中缺少name或age字段时,通用解析器仍然会报错。

解决方法

要为单个缺失字段设置默认值,需要在genericParseJSON的配置选项中通过fieldDefaults指定每个字段的默认值。以下是两种可行的实现方式:

方式一:直接指定字段默认值

无需额外依赖,直接在配置中为每个字段定义默认的JSON值:

import           Data.Aeson
import           Data.Aeson.Types (Value(..))
import           GHC.Generics

data Person = Person
  { name :: String
  , age  :: Int
  } deriving (Generic, Show)

instance FromJSON Person where
  parseJSON = genericParseJSON defaultOptions
    { allowOmittedFields = True  -- 允许字段被省略
    , fieldDefaults = DefaultFieldUse $ \fieldName -> case fieldName of
        "name" -> Just $ String "Unnamed"  -- name字段缺失时用"Unnamed"
        "age" -> Just $ Number (-1)        -- age字段缺失时用-1
        _ -> Nothing
    }

main :: IO ()
main = do print (eitherDecode @Person "{}")
          print (eitherDecode @Person "{\"name\":\"Bob\"}")
          print (eitherDecode @Person "{\"name\":\"Bob\",\"age\":42}")

方式二:结合Default类型类(更优雅)

导入Data.Default包,为Person实现默认实例,再复用该实例的字段值作为默认值:

import           Data.Aeson
import           Data.Default (Default(..))
import           Data.Aeson.Types (toJSON)
import           GHC.Generics

data Person = Person
  { name :: String
  , age  :: Int
  } deriving (Generic, Show)

-- 定义Person的默认实例
instance Default Person where
  def = Person "Unnamed" (-1)

instance FromJSON Person where
  parseJSON = genericParseJSON defaultOptions
    { allowOmittedFields = True
    , fieldDefaults = DefaultFieldUse $ \fieldName -> case fieldName of
        "name" -> Just $ toJSON (def.name)
        "age" -> Just $ toJSON (def.age)
        _ -> Nothing
    }

main :: IO ()
main = do print (eitherDecode @Person "{}")
          print (eitherDecode @Person "{\"name\":\"Bob\"}")
          print (eitherDecode @Person "{\"name\":\"Bob\",\"age\":42}")
运行结果

修正后的代码运行后会得到预期输出:

Right (Person {name = "Unnamed", age = -1})
Right (Person {name = "Bob", age = -1})
Right (Person {name = "Bob", age = 42})

内容的提问来源于stack exchange,提问作者Futarimiti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:05:33