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 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置