Как декодировать большое число из JSON в Swift - PullRequest
0 голосов
/ 03 октября 2019

Как мне разобрать 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

Я бы не возражал, получая его как String или Data, но это недопустимо, потому что JSONDecoder знает, что это должно быть число:

Expected to decode String but found a number instead.

Ответы [ 2 ]

4 голосов
/ 03 октября 2019

Вместо этого можно использовать 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)

Decimal - это тип оверлея Swift NSDecimalNumber, который

.. . может представлять любое число, которое может быть выражено как mantissa x 10^exponent, где мантисса - это десятичное целое число длиной до 38 цифр, а экспонента - это целое число от –128 до 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)
0 голосов
/ 04 октября 2019

Похоже, что JSONDecoder использует 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.


Обратите внимание, что в то время как документация говорит, что

мантисса является десятичным целым числом вверхдо 38 цифр

На самом деле это 128-разрядное целое число без знака, поэтому оно может также представлять около 39 цифр, как показано выше.

...