为了账号安全,请及时绑定邮箱和手机立即绑定

填充作为参数给出的接口类型的一部分(例如,为数据库/sql 实现 ScanAll)

填充作为参数给出的接口类型的一部分(例如,为数据库/sql 实现 ScanAll)

Go
青春有我 2023-05-08 14:35:00
我们如何实现一个函数,该函数将返回 SQL 查询产生的所有行并将它们转换为dest接口数组(可能无法正常工作Scan)?我假设目标数组必须作为函数的参数给出。但是,我仍然不知道我应该如何完成实施:func GetAll(query string, dest interface{}) error {  rows, err := s.db.Query(query)  if err != nil {    return err  }  defer rows.Close()  for rows.Next() {    var destRow ??? /* do not have a type. using reflect.TypeOf(dest).Elem()? */    err := rows.Scan(&destRow)    if err != nil {      return err    }    dest = append(dest, destRow) /* would even compile? */  }  return nil}它看起来与json.Unmarshal实际必须做的没什么不同......
查看完整描述

1 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

这是使用reflect 包的解决方案。使用指向切片的指针调用函数。

func GetAll(query string, dest interface{}) error {


    // Return error if dest is not a pointer to a slice.

    slice := reflect.ValueOf(dest)

    if slice.Kind() != reflect.Ptr {

        return errors.New("dest must be pointer")

    }

    slice = slice.Elem()

    if slice.Kind() != reflect.Slice {

        return errors.New("dest must be pointer to struct")

    }


    rows, err := db.Query(query)

    if err != nil {

        return err

    }

    defer rows.Close()


    for rows.Next() {

        // Create a new slice element. The variable elementp holds a 

        // pointer to the new element.

        elementp := reflect.New(slice.Type().Elem())


        err := rows.Scan(elementp.Interface())

        if err != nil {

            return err

        }


        // Append the element to the slice.

        slice.Set(reflect.Append(slice, elementp.Elem()))

    }

    return nil

}

当查询结果只有一列并且 dest 是指向适合该列的类型的切片时,上面的代码适用于标准的 database/sql 包。这是一个例子:


var names []string

if err := GetAll(db, "select name from people", &names); err != nil {

    // handle error

}

此代码还应与支持将多列扫描到结构的数据库包一起使用。


查看完整回答
反对 回复 2023-05-08
  • 1 回答
  • 0 关注
  • 83 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信