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

Haskell中如何处理Jogo数据类型JSON解析字段类型不匹配问题

类型不匹配解析异常处理方案

你当前使用aeson默认的Generic派生FromJSON实例,对JSON字段类型有严格校验,一旦字段类型和定义不匹配就会触发全局解析失败返回Nothing,可通过以下方案处理:

方案1:自定义兼容多类型的FromJSON实例

如果确定数值字段只会偶尔被误存为字符串格式的数字(比如"5"),可以自定义解析逻辑同时兼容数字和字符串类型:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

import GHC.Generics (Generic)
import Data.Aeson (FromJSON, Value(..), withObject, (.:))
import Data.Aeson.Types (Parser)
import Data.Text (unpack)
import Text.Read (readMaybe)
import Control.Applicative ((<|>))

data Jogo = JogoInstance {
    rodada, golsMandante, golsVisitante :: Int,
    timeMandante, timeVisitante :: String
} deriving (Generic, Show)

instance FromJSON Jogo where
  parseJSON = withObject "Jogo" $ \v -> JogoInstance
    <$> v .: "rodada"
    <*> parseFlexibleInt "golsMandante" v
    <*> parseFlexibleInt "golsVisitante" v
    <*> v .: "timeMandante"
    <*> v .: "timeVisitante"
  where
    parseFlexibleInt field obj = do
      val <- obj .: field
      case val of
        -- 兼容数字类型输入
        Number n -> pure $ truncate n
        -- 兼容字符串格式的数字输入
        String s -> case readMaybe (unpack s) of
          Just intVal -> pure intVal
          Nothing -> fail $ "字段" <> field <> "的值" <> unpack s <> "无法转为数字"
        _ -> fail $ "字段" <> field <> "必须为数字或数字格式字符串"

方案2:优化错误输出,快速定位问题

默认的decode函数只会返回Nothing没有错误信息,换成eitherDecode可以拿到具体的解析失败原因,方便排查数据错误:

import Data.Aeson (eitherDecode)
import qualified Data.ByteString.Lazy as B

lerJSON :: IO [Jogo]
lerJSON = do
  input <- B.readFile "db/jogos.json"
  case eitherDecode input of
    -- 打印错误信息后返回空列表,也可根据需求抛出异常或写入日志
    Left err -> do
      putStrLn $ "JSON解析失败:" <> err
      return []
    Right jogos -> return jogos

方案3:单条数据错误不影响整体加载

如果希望个别无效数据被自动忽略,不要导致整个列表解析失败,可以先解析为JSON值数组,再逐条解析过滤:

import Data.Aeson (eitherDecode, encode, FromJSON, Value)
import Control.Monad (unless)
import qualified Data.ByteString.Lazy as B

lerJSON :: IO [Jogo]
lerJSON = do
  input <- B.readFile "db/jogos.json"
  case eitherDecode input of
    Left err -> do
      putStrLn $ "JSON结构解析失败:" <> err
      return []
    Right (valueList :: [Value]) -> do
      let parseResults = map parseSingle valueList
          validJogos = [j | Right j <- parseResults]
          invalidErrs = [e | Left e <- parseResults]
      -- 打印无效数据数量和示例错误
      unless (null invalidErrs) $ putStrLn $ "忽略了" <> show (length invalidErrs) <> "条无效数据,首个错误:" <> head invalidErrs
      return validJogos
  where
    parseSingle v = eitherDecode (encode v) :: Either String Jogo

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 18:15:00