Как строго разобрать массив с фиксированной длиной? - PullRequest
0 голосов
/ 24 мая 2019

У меня есть координаты, возвращающиеся в JSON

Хотя API всегда должен возвращать их корректно в виде массива размера 2, как мы можем обеспечить правильность структуры и выдавать ошибку при демаршалинге (не считая очень ручного процесса). Смотрите пример случая, если JSON является недействительным.

package main

import (
    "fmt"
    "encoding/json"
)

// ResultType
type Location struct {
    Coordinates [2]int `json:"coords,array[20]"`
}

func main() {
    fmt.Println("Hello, playground")

    result := Location{}
    jsonBodyTooManyCoords := `{"coords": [1, 2, 3]}`
    json.Unmarshal([]byte(jsonBodyTooManyCoords), &result)
    fmt.Println(result) // Prints {1, 2}

    result = Location{}
    jsonBodyTooManyCoords = `{"coords": [1]}`
    json.Unmarshal([]byte(jsonBodyTooManyCoords), &result)
    fmt.Println(result) // Prints {1, 0}
}

Ответы [ 2 ]

1 голос
/ 24 мая 2019

[H] как мы можем обеспечить правильность структуры и выдать ошибку при демаршалинге [...]?

Вы не можете.

Избыточные элементы отбрасываются молча, а пропущенные значения возвращаются как нулевое значение (оба факта задокументированы в документации по encoding / json).

Также обратите внимание, что модификатора массива нет, поэтому ваши теги struct json:"cords,array[20]" кажется странным.

Если вы хотите / должны обрабатывать искаженный массив JSON: разберите на фрагмент и проверьте его длину.

0 голосов
/ 24 мая 2019

Для такого применения требуется пользовательский тип и пользовательский демаршалер. Вы могли бы сделать что-то вроде этого:

type coord [2]int

func (c *coord) UnmarshalJSON(data []byte) error {
    var x []int
    if err := json.Unmarshal(data, &x); err != nil {
        return err
    }
    if len(x) > 2 {
        return errors.New("Too many values")
    }
    if len(x) < 2 {
        return errors.New("Too few values")
    }
    copy((*c)[:], x)
    return nil
}

Тогда используйте ваш пользовательский тип:

// ResultType
type Location struct {
    Coordinates coord `json:"coords,array[20]"`
}
...