如何在PureScript中使用Argonaut实现异构类型数组的JSON编解码
Argonaut 异构类型数组编解码实现方案
Argonaut 没有原生的异构数组自动编解码支持,你可以通过自定义总和类型+自定义编解码规则的方式实现需求,以下是完整实现步骤:
步骤1:定义异构元素适配类型
首先定义可以覆盖数组内所有元素类型的总和类型,用于承载异构数据:
-- 适配数组可能出现的所有元素类型:数值/字符串 data HeteroItem = NumItem Number | StrItem String -- 按需推导通用实例 derive instance eqHeteroItem :: Eq HeteroItem derive instance showHeteroItem :: Show HeteroItem
如果你的异构数组是固定长度、固定类型顺序的场景(比如示例中固定第一个是数值、第二个是字符串),可以跳过定义总和类型,直接在结构体编解码规则里做强校验,实现更简单。
步骤2:实现解码逻辑(DecodeJson 实例)
任意长度异构数组解码
自定义解码规则,按优先级尝试匹配元素类型,匹配失败返回解码错误:
import Data.Argonaut.Decode (class DecodeJson, decodeJson, (<?>)) import Data.Alt ((<|>)) instance decodeJsonHeteroItem :: DecodeJson HeteroItem where decodeJson json = (NumItem <$> decodeJson json) <|> (StrItem <$> decodeJson json) <?> "expected number or string type"
固定顺序异构数组解码
如果你的数组固定为「数值+字符串」的二元结构,可以直接在父结构体的解码规则里做强校验,不需要单独定义总和类型:
import Data.Argonaut.Decode (class DecodeJson, withObject, (.:), fail) import Data.Array (index, length) -- 业务结构体定义 type MyStruct = { field :: { numVal :: Number, strVal :: String } } instance decodeJsonMyStruct :: DecodeJson MyStruct where decodeJson = withObject "MyStruct" \obj -> do arr <- obj .: "field" if length arr /= 2 then fail "field must be an array with exactly 2 elements" else do num <- decodeJson =<< index arr 0 str <- decodeJson =<< index arr 1 pure { field: { numVal: num, strVal: str } }
步骤3:实现编码逻辑(EncodeJson 实例)
任意长度异构数组编码
根据类型分支编码为对应JSON类型即可:
import Data.Argonaut.Encode (class EncodeJson, encodeJson) instance encodeJsonHeteroItem :: EncodeJson HeteroItem where encodeJson (NumItem n) = encodeJson n encodeJson (StrItem s) = encodeJson s
固定顺序异构数组编码
对应固定顺序的二元数组场景,编码逻辑如下:
import Data.Argonaut.Encode (class EncodeJson, object, (:=)) instance encodeJsonMyStruct :: EncodeJson MyStruct where encodeJson struct = object [ "field" := [ encodeJson struct.field.numVal, encodeJson struct.field.strVal ] ]
效果验证
-- 任意长度异构数组编解码测试 testArr :: Array HeteroItem testArr = [NumItem 3.0, StrItem "text"] encodedArr = encodeJson testArr -- 输出JSON: [3,"text"] decodedArr = decodeJson (encodeJson testArr) :: Either _ (Array HeteroItem) -- 输出: Right [NumItem 3.0, StrItem "text"] -- 固定顺序异构数组编解码测试 testStruct :: MyStruct testStruct = { field: { numVal: 3.0, strVal: "text" } } encodedStruct = encodeJson testStruct -- 输出JSON: {"field":[3,"text"]} decodedStruct = decodeJson (encodeJson testStruct) :: Either _ MyStruct -- 输出: Right { field: { numVal: 3.0, strVal: "text" } }
内容的提问来源于stack exchange,提问作者QSpider
相关产品推荐
相关产品推荐

