code: func (p *Collector) Retrieve(ctx context.Context, objs []types.ManagedObjectReference, ps []string, dst interface{}) error {
  	if len(objs) == 0 {
  		return errors.New("object references is empty")
  	}
  
  	kinds := make(map[string]bool)
  
  	var propSet []types.PropertySpec
  	var objectSet []types.ObjectSpec
  
  	for _, obj := range objs {
  		if _, ok := kinds[obj.Type]; !ok {
  			spec := types.PropertySpec{
  				Type: obj.Type,
  			}
  			if ps == nil {
  				spec.All = types.NewBool(true)
  			} else {
  				spec.PathSet = ps
  			}
  			propSet = append(propSet, spec)
  			kinds[obj.Type] = true
  		}
  
  		objectSpec := types.ObjectSpec{
  			Obj:  obj,
  			Skip: types.NewBool(false),
  		}
  
  		objectSet = append(objectSet, objectSpec)
  	}
  
  	req := types.RetrieveProperties{
  		SpecSet: []types.PropertyFilterSpec{
  			{
  				ObjectSet: objectSet,
  				PropSet:   propSet,
  			},
  		},
  	}
  
  	res, err := p.RetrieveProperties(ctx, req)
  	if err != nil {
  		return err
  	}
  
  	if d, ok := dst.(*[]types.ObjectContent); ok {
  		*d = res.Returnval
  		return nil
  	}
  
  	return mo.LoadRetrievePropertiesResponse(res, dst)
  }
docs: // Retrieve loads properties for a slice of managed objects. The dst argument
  // must be a pointer to a []interface{}, which is populated with the instances
  // of the specified managed objects, with the relevant properties filled in. If
  // the properties slice is nil, all properties are loaded.
  // Note that pointer types are optional fields that may be left as a nil value.
  // The caller should check such fields for a nil value before dereferencing.