Как сделать маршал и демаршал big.Int в JSON? - PullRequest
0 голосов
/ 01 января 2019

Вопрос Как выполнить маршализацию JSON с bigints? о маршалинге big.Int значений в строки в JSON.Этот вопрос спрашивает, как один маршал и немаршал big.Int изначально имеют значения как числа в JSON?

Передача больших значений, маршалированных таким образом, может быть несовместима сдругие реализации JSON, в частности JavaScript и jq , а RFC 7159 отмечает:

Обратите внимание, что при использовании такого программного обеспечения числа, которые являются целыми числами и являютсяв диапазоне [-(2**53)+1, (2**53)-1] совместимы в том смысле, что реализации будут точно согласовывать их числовые значения.

1 Ответ

0 голосов
/ 01 января 2019

Создайте пользовательский тип BigInt, который реализует json.Marshaler и json.Unmarshaler, как показано ниже:

import (
    "fmt"
    "math/big"
)

type BigInt struct {
    big.Int
}

func (b BigInt) MarshalJSON() ([]byte, error) {
    return []byte(b.String()), nil
}

func (b *BigInt) UnmarshalJSON(p []byte) error {
    if string(p) == "null" {
        return nil
    }
    var z big.Int
    _, ok := z.SetString(string(p), 10)
    if !ok {
        return fmt.Errorf("not a valid big integer: %s", p)
    }
    b.Int = z
    return nil
}

Обоснование:

  • Реализовано как внедрение типа структуры big.Int вместо подтипа big.Int, чтобы методы (Add, SetString и т. Д.) Сохранялись
  • MarshalJSON принимает получатель значений, чтобы маршализованные значения, использующие BigInt, не использовалиpointers
  • UnmarshalJSON принимает указатель получателя, потому что он изменяет получатель;однако типы, использующие BigInt, по-прежнему не должны использовать указатели
  • UnmarshalJSON работает с временным значением, поскольку метод SetString имеет неопределенное поведение на своем получателе в случае ошибок

Asс big.Int нулевое значение полезно и равно числу 0.

...