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

泛型容器可选类型nil值JSON编码不省略的解决方法问询

泛型Codable类型处理nil值序列化的问题

当使用JSONEncoder对包含可选属性的Encodable类型执行编码时,nil值会被自动省略,最终生成空的JSON结构,以下测试用例可验证该行为:

func test_whenNilValueIsSerialised_thenItIsOmitted() throws {
    struct Container: Codable {
        let cargo: Int?
    }

    let encoding = try XCTUnwrap(String(bytes: JSONEncoder().encode(Container(cargo: nil)), encoding: .utf8))
    XCTAssertEqual(encoding, "{}")
}

但如果是泛型Codable类型,且将可选类型作为泛型参数传入时,上述自动省略nil的行为失效,以下测试用例会执行失败:

func test_whenNilValueFromGenericIsSerialised_thenItIsOmitted() throws {
    struct Container<Cargo: Codable>: Codable {
        let cargo: Cargo
    }

    let container = Container<String?>(cargo: nil)
    let encoding = try XCTUnwrap(String(bytes: JSONEncoder().encode(container), encoding: .utf8))

    XCTAssertEqual(encoding, "{}")
}

失败报错信息:

XCTAssertEqual failed: ("{"cargo":null}") is not equal to ("{}")

问题:是否存在简洁的解决方案?比如为Container实现显式的encode(to:)方法?

注:直接将属性定义为let cargo: Cargo?的方案不适用,因为多数场景下需要使用非可选类型作为Cargo参数。


解决方案:自定义encode(to:)方法

可以通过实现自定义的encode(to:)方法,在编码时判断cargo是否为nil(仅当Cargo为可选类型时),若为nil则跳过该字段,否则正常编码。

struct Container<Cargo: Codable>: Codable {
    let cargo: Cargo
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        // 识别可选类型的nil值并跳过编码
        switch cargo {
        case Optional<Any>.none:
            break
        default:
            try container.encode(cargo, forKey: .cargo)
        }
    }
    
    enum CodingKeys: String, CodingKey {
        case cargo
    }
}

修改后,上述失败的测试用例会顺利通过:当Cargo是可选类型且值为nil时,cargo字段会被省略,生成{};当Cargo是非可选类型时,会正常编码该字段。

如果需要更严谨的类型检查,也可以通过Mirror或类型判断来确认Cargo为可选类型后再处理,但上述switch的方式已经能覆盖绝大多数场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 00:28:10