You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Go反射设置slice接口值,填充Mongo查询返回的泛型指针数组

Go语言Mongo泛型结果填充问题修复方案

错误根因

Go类型系统中,[]interface{}和[]Person是完全独立的两种类型,即便Person可以存入interface{},切片整体也不支持直接赋值。你直接将[]interface{}类型的反射值写入[]Person类型的接收变量,就会触发类型不匹配的panic。

修复方案

方案1:反射实现(兼容Go 1.18之前版本)

修改后的getListWithCount函数会先获取接收切片的元素类型,逐个转换Mongo返回的文档后再写入切片:

import "errors"
import "reflect"
import "go.mongodb.org/mongo-driver/bson"
import "go.mongodb.org/mongo-driver/bson/primitive"

func getListWithCount(ctx context.Context, receiver interface{}) (int, error) {
    // 原有Mongo查询逻辑保持不变
    var mongoResp struct {
        Total     int         `bson:"total"`
        Documents interface{} `bson:"documents"`
    }
    if err := cursor.Decode(&mongoResp); err != nil {
        return 0, err
    }

    // 校验入参类型合法性
    receiverValue := reflect.ValueOf(receiver)
    if receiverValue.Kind() != reflect.Ptr {
        return 0, errors.New("receiver must be a slice pointer")
    }
    sliceValue := receiverValue.Elem()
    if sliceValue.Kind() != reflect.Slice {
        return 0, errors.New("receiver must point to a slice")
    }
    elemType := sliceValue.Type().Elem()

    docs := mongoResp.Documents.(primitive.A)
    // 构造和返回结果长度一致的目标类型切片
    newSlice := reflect.MakeSlice(sliceValue.Type(), len(docs), len(docs))
    for i, rawDoc := range docs {
        // BSON序列化反序列化完成类型转换
        bsonData, err := bson.Marshal(rawDoc)
        if err != nil {
            return 0, err
        }
        elemPtr := reflect.New(elemType).Interface()
        if err := bson.Unmarshal(bsonData, elemPtr); err != nil {
            return 0, err
        }
        newSlice.Index(i).Set(reflect.ValueOf(elemPtr).Elem())
    }
    // 赋值给入参接收变量
    sliceValue.Set(newSlice)

    return mongoResp.Total, nil
}

方案2:泛型实现(Go 1.18+ 推荐,无反射开销)

使用泛型可以彻底避免反射操作,代码更简洁易维护:

import "log"
import "fmt"
import "context"
import "go.mongodb.org/mongo-driver/bson"

func getListWithCount[T any](ctx context.Context) (int, []T, error) {
    // 原有Mongo查询逻辑保持不变
    var mongoResp struct {
        Total     int   `bson:"total"`
        Documents []T   `bson:"documents"`
    }
    if err := cursor.Decode(&mongoResp); err != nil {
        return 0, nil, err
    }
    return mongoResp.Total, mongoResp.Documents, nil
}

// 调用示例
type Person struct {
    Name string `bson:"name"`
}

func main() {
    count, persons, err := getListWithCount[Person](context.Background())
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(count)
    fmt.Println(persons)
}

内容的提问来源于stack exchange,提问作者Ado Ren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 09:18:04