1 Вопрос: Функция Go принимает другой параметр массива

вопрос создан в Wed, May 8, 2019 12:00 AM

Я хочу использовать универсальную функцию для демонтажа различных типов:

type Foo struct {
  Name    string
  Another string
}

type Bar struct {
  Name  string
  Some  string
}

func unmarshal(data []byte, val *[]map[string]interface{}) {
  err := json.Unmarshal(data, val)

  if err != nil || (*val)[0]["Name"] == "" {
    *val = nil
  }
}

func main() {
  var foos []Foo
  var bars []Bar

  // fooData and barData are JSON strings retrieved from database
  unmarshal(fooData, &foos)
  unmarshal(barData, &bars)
}

Я получил ошибку, например cannot use &foo (type *[]Foo) as type *[]map[string]interface {} in argument to unmarshal.

Я пытался использовать val interface{} в качестве параметра, но он не поддерживает индекс.

Как я могу достичь цели? Спасибо.

    
- 5
  1. Компилятор сообщает, что вы передаете указатель на фрагмент Foo , но функция ожидает указатель на ломтик map[string]interface{} . Это явно не сработает, потому что Foo - это не карта.
    2019-05-08 16: 11: 26Z
1 ответ                              1                         

Для работы с произвольными типами срезов объявите аргумент как тип interface{} и используйте отражение , чтобы получить доступ к значению: р>

func unmarshal(data []byte, v interface{}) {
    err := json.Unmarshal(data, v)
    rv := reflect.ValueOf(v).Elem()

    if err != nil || rv.Len() == 0 || rv.Index(0).FieldByName("Name").Interface() == "" {
        rv.Set(reflect.Zero(rv.Type()))
    }
}
    
2
2019-05-08 16: 45: 04Z
  1. Это работает! Благодарю. Еще одна вещь, если имя поля не существует, код будет паниковать по panic: reflect: call of reflect.Value.Interface on zero Value. Как я могу выполнить некоторую предварительную проверку, чтобы сделать код сильнее?
    2019-05-09 01: 28: 14Z
  2. Убедитесь, что значение, возвращаемое из FieldByNsme, является допустимым перед вызовом интерфейса. godoc.org/reflect#Value.IsValid
    2019-05-09 01: 56: 24Z
источник размещен Вот