【问题标题】:How to pass array of struct as interface by reference如何通过引用将结构数组作为接口传递
【发布时间】:2020-03-02 17:40:38
【问题描述】:

我正在尝试读取给定 Firestore 集合下的所有文档,并将文档作为结构数组返回。函数内的日志将数据输出为 Firestore 文档,但函数外的 struct 数组始终为空数组。

读取集合下所有文档的函数。

func (fc *FirebaseClient) ReadCollection(collectionPath string, objects interface{}) error {
    ctx := context.Background()
    opt := option.WithCredentialsJSON([]byte(os.Getenv("FIREBASE_CREDENTIALS")))
    client, err := firestore.NewClient(ctx, os.Getenv("FIREBASE_PROJECT_ID"), opt)
    if err != nil {
        return err
    }
    defer client.Close()

    collectionRef := client.Collection(collectionPath)
    docs, err := collectionRef.DocumentRefs(ctx).GetAll()
    if err != nil {
        return err
    }
    log.Printf("Total documents: %i", len(docs))
    objs := make([]interface{}, len(docs))
    for i, doc := range docs {
        docsnap, err := doc.Get(ctx)
        if err != nil {
            return err
        }

        if err := docsnap.DataTo(&objs[i]); err != nil {
            return err
        }
        log.Printf("obj: %v", objs[i])

    }

    objects = objs
    log.Printf("objects: %v", objects)
    return nil
}

调用函数的代码

    var ss []SomeStruct

    fc := new(insightech.FirebaseClient)
    if err := fc.ReadCollection("mycollection", ss); err != nil {
        return
    }

ss 始终是一个空数组。

我不想指定结构类型的原因是使 ReadCollection 函数具有通用性,以便我可以调用它来读取不同的集合。

代码不会触发任何错误,但结果是一个空数组,即使objects 接口肯定是一个包含元素的数组。

【问题讨论】:

  • 这怎么可能?看看标准库是如何做这些事情的,例如在编码/json中。
  • 重新分配对象对调用者没有任何作用。这就像你传递一个 int 一样。在 Go 中,一切都是按值传递的。
  • 如果interface{} 被分配为一个结构,它就可以工作。我可以读取单个文档(读取文档而不是集合的不同代码)并更新传递给函数的结构中的值。
  • 这绝对应该是@​​mkopriva所说的指针
  • @ChaomingLi 你必须传递一个指针,没有办法解决这个问题,但是你的实现还有很多问题,这就是为什么“没有区别”。

标签: arrays go struct interface


【解决方案1】:

感谢@mkopriva,以下代码有效:

func (fc *FirebaseClient) ReadCollection(collectionPath string, objects interface{}) error {
    ctx := context.Background()
    opt := option.WithCredentialsJSON([]byte(os.Getenv("FIREBASE_CREDENTIALS")))
    client, err := firestore.NewClient(ctx, os.Getenv("FIREBASE_PROJECT_ID"), opt)
    if err != nil {
        return err
    }
    defer client.Close()

    collectionRef := client.Collection(collectionPath)
    docs, err := collectionRef.DocumentRefs(ctx).GetAll()
    if err != nil {
        return err
    }
    log.Printf("Total documents: %i", len(docs))

    dest := reflect.ValueOf(objects).Elem()


    log.Printf("dest: %v", dest)
    for _, doc := range docs {
        docsnap, err := doc.Get(ctx)
        if err != nil {
            return err
        }

        obj := reflect.New(dest.Type().Elem())

        if err := docsnap.DataTo(obj.Interface()); err != nil {
            return err
        }
        log.Printf("obj: %v", obj)
        dest = reflect.Append(dest, obj.Elem())


    }

    reflect.ValueOf(objects).Elem().Set(dest)
    log.Printf("objects: %v", dest)
    return nil
}
    var ss []SomeStruct

    fc := new(insightech.FirebaseClient)
    if err := fc.ReadCollection("mycollection", &ss); err != nil {
        return
    }

【讨论】:

    猜你喜欢
    • 2020-12-07
    • 2014-12-13
    • 1970-01-01
    • 2017-11-29
    • 2019-10-30
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多