doufendi9063 2018-11-05 18:15
浏览 36
已采纳

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

How could we implement a function which would return all rows resulting from a SQL query and convert them to dest which is an interface array (may not work as Scan) ?

I assume the destination array would have to be given as an argument to the function. But then, I still do not know how I am supposed to complete the implementation:

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
}

It does not look like much different from what json.Unmarshal have to do actually...

  • 写回答

1条回答 默认 最新

  • dsjzmrz78089 2018-11-06 08:01
    关注

    Here's a solution using the reflect package. Call the function with a pointer to a slice.

    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
    }
    

    The above code works with standard database/sql package when the query result has a single column and dest is a pointer to a slice of a type appropriate for that column. Here's an example:

    var names []string
    if err := GetAll(db, "select name from people", &names); err != nil {
        // handle error
    }
    

    This code should also work with a database package that supports scanning multiple columns to a struct.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100