如何在 Swift 中解码 JSON 中的大数

How to decode a large number from JSON in Swift

如何像这样解析 JSON:

let json = "{\"key\":18446744073709551616}"

struct Foo: Decodable {
    let key: UInt64
}

let coder = JSONDecoder()
let test = try! coder.decode(Foo.self, from: json.data(using: .utf8)!)

问题是这个数字对于 UInt64 来说太大了。我知道 Swift.

中没有更大的整数类型
Parsed JSON number <18446744073709551616> does not fit in UInt64

我不介意将其设为 StringData,但这是不允许的,因为 JSONDecoder 知道它应该是一个数字:

Expected to decode String but found a number instead.

您可以使用 Decimal 代替:

let json = "{\"key\":184467440737095516160000001}"

struct Foo: Decodable {
    let key: Decimal
}

let coder = JSONDecoder()
let test = try! coder.decode(Foo.self, from: json.data(using: .utf8)!)
print(test) // Foo(key: 184467440737095516160000001)

DecimalNSDecimalNumber 的 Swift 覆盖类型,

... can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.

如果不需要完全精度,您也可以将其解析为 Double

struct Foo: Decodable {
    let key: Double
}

let coder = JSONDecoder()
let test = try! coder.decode(Foo.self, from: json.data(using: .utf8)!)
print(test) // Foo(key: 1.8446744073709552e+36)

似乎是JSON解码器在幕后使用NSDecimalNumber

struct Foo: Decodable {
    let key: Int
}

// this is 1 + the mantissa of NSDecimalNumber.maximum
let json = "{\"key\":340282366920938463463374607431768211456}"
let coder = JSONDecoder()
let test = try! coder.decode(Foo.self, from: json.data(using: .utf8)!)

即使在 DecodingError 中,数字也没有准确表示:

Parsed JSON number <340282366920938463463374607431768211450> does not fit in Int.

因此,如果您希望能够以最大精度解码(尽管您仍然可能会默默地失去精度),请使用 Decimal。否则你只需要对发给你的人大喊大叫 JSON.


请注意,虽然 documentation 表示

mantissa is a decimal integer up to 38 digits

它实际上是一个 128 位无符号整数,因此它也可以表示一些 39 位数字,如上所示。