Я борюся з deserializing ціле урядок структури структури. Поле struct є рядком і, як очікується, буде призначатися користувачам моєї бібліотеки. Ось чому я хочу, щоб це була рядок, оскільки для запису в базу даних я дійсно не дбаю про значення всередині. Користувачі можуть надавати текст, але деякі просто призначають цілі числа.
Розглянемо цю структуру:
type Test struct {
Foo string
}
Іноді я отримую значення JSON, яке є дійсним, але не "deserialize" у структуру, оскільки поле Foo є цілим числом замість рядка:
{ "foo": "1" } // works
{ "foo": 1 } // doesn"t
json.Unmarshal вибухне з такою помилкою:
json: cannot unmarshal number into Go struct field test.Foo of type string
Див. https://play.golang.org/p/4Qau3umaVm
Тепер у кожній іншій бібліотеці JSON (в іншійЯ працював до цих пір, якщо цільове поле - це рядок, і ви отримаєте ціле число, то десеріализатор, як правило, просто обертає int в рядок і виконується з ним. Чи може це бути досягнуто в Go?
Так як я дійсно не можу контролювати, як надходять дані, мені потрібно зробити json.Unmarshal
Нечутливий до цього - іншим рішенням було б визначити Foo as interface{}
які безпідставно ускладнюють мій код з типовими твердженнями тощо.
Будь-які ідеї про те, як це зробити? Я в основному потребую зворотного json:",string"
Відповіді:
5 за відповідь № 1Для обробки великих структур можна використовувати вбудовування.
Оновлено, щоб не відкидати, можливо, попередньо встановлені значення полів.
func (t *T) UnmarshalJSON(d []byte) error {
type T2 T // create new type with same structure as T but without its method set!
x := struct{
T2 // embed
Foo json.Number `json:"foo"`
}{T2: T2(*t)} // don"t forget this, if you do and "t" already has some fields set you would lose them
if err := json.Unmarshal(d, &x); err != nil {
return err
}
*t = T(x.T2)
t.Foo = x.Foo.String()
return nil
}
https://play.golang.org/p/BytXCeHMvt
1 для відповіді № 2
Ви можете налаштувати, як структура даних буде розмежовуватися шляхом реалізації json.Unamrshaler
інтерфейс
Найпростіший спосіб обробляти невідомі типи - nnmarshal JSON в проміжну структуру і обробляти твердження типу і перевірку під час десериализации:
type test struct {
Foo string `json:"foo"`
}
func (t *test) UnmarshalJSON(d []byte) error {
tmp := struct {
Foo interface{} `json:"foo"`
}{}
if err := json.Unmarshal(d, &tmp); err != nil {
return err
}
switch v := tmp.Foo.(type) {
case float64:
t.Foo = strconv.Itoa(int(v))
case string:
t.Foo = v
default:
return fmt.Errorf("invalid value for Foo: %v", v)
}
return nil
}
https://play.golang.org/p/t0eI4wCxdB