Go и пользовательский тип структуры в другой структуре

Я изо всех сил пытаюсь понять, как сохранить пользовательскую структуру в другой структуре (среди многих других вещей). В настоящее время мой код выглядит так:

type dogs struct {
  bleeh string
  blaah string
  bluuh string
}

type Stuff struct {
  collection      *mgo.Collection
  //myAnimalStruct what type comes here?
}

func NewStuff(c *mgo.Collection) *Stuff {
  return &Stuff{
    collection: c
  }
}

func getAll(s *Stuff) interface{} {
  collection = s.collection
  var results []dogs
  err := collection.Find(bson.M{}).All(&results)
  if err != nil {
    panic(err)
  }
  return results
}

Теперь я хотел бы избавиться от этого var results []dogs в функции getAll. Вместо этого я хотел бы каким-то образом получить этот бит []dogs из моей структуры Stuff, но я не могу понять, как это сделать.

вот как я вызываю эту функцию:

func getMeDogs(w http.ResponseWriter, r *http.Request) interface{} {
  collection = Collection("animals")
  s := NewStuff(collection)
  return getAll(s)
}

Итак, как я мог сделать что-то вроде s := NewStuff(коллекция, собаки) с моей структурой Stuff, не объявляя ее как тип собаки в Stuff (это может быть что угодно, в другой функции это могут быть кошки, насколько я знаю...) ?

Дело в том, что я хочу повторно использовать эту функцию getAll для любых других типов вместо того, чтобы создавать почти идентичную функцию getAll для всех моих 63 животных. Мяу.


person QlliOlli    schedule 10.09.2014    source источник


Ответы (1)


Вы можете сохранить прототипное значение типа в Stuff и использовать отражение для создания указателя на значение этого типа.

type Stuff struct {
    collection  *mgo.Collection
    v           interface{}   // the prototype value
}

func NewStuff(c *mgo.Collection, v interface{}) *Stuff {
    return &Stuff{
      collection: c,
      v: v,
    }
}

func getAll(s *Stuff) (interface{}, error) {
   p := reflect.New(reflect.TypeOf(s.v))
   if err := s.collection.Find(bson.M{}).All(p.Interface()); err != nil {
      return nil, err
   }
   return p.Elem().Interface(), nil
}

Чтобы создать коллекцию Dog:

s := NewStuff(collection, []Dog{})

Некоторые люди скажут, что отражение происходит медленно. Это правда, но в этом случае стоимость невелика по сравнению со стоимостью выполнения Find().All(). Вызов Find().All() отправляет запрос на сервер базы данных и ожидает ответа. Ответ от сервера распаковывается с помощью декодера Mgo BSON. Декодер BSON интенсивно использует отражение.

person Simon Fox    schedule 10.09.2014