我正在使用denisenkom中的示例运行SQL查询,但与http.ResponseWriter结合使用,并且我在interface{}类型转换方面苦苦挣扎。有几篇帖子与我正在做的事情很接近,但是解决方案似乎有点笨拙,总是使用fmt(我没有使用)。

请注意,我的查询有效并返回结果。我只是想显示该结果。

这是我认为比较接近但无法正常工作的代码。我尝试了其他几件事,但什至没有编译。

vals := make([]interface{}, len(cols))
for i := 0; i < len(cols); i++ {
        vals[i] = new(interface{})
        if i != 0 {
                w.Write([]byte("\t"))
        }
        w.Write([]byte(cols[i]))
}

for rows.Next() {
      err = rows.Scan(vals...)
      if err != nil {
          w.Write([]byte("Row problem: " + err.Error()))
          continue
      }
      for i := 0; i < len(vals); i++ {
          if i != 0 {
              w.Write([]byte("\t"))
          }

      //THIS IS THE PART I'M STUCK ON
      switch v := vals[i].(type) {
      case int:
           w.Write([]byte("int!\n" + string(v)))
      case int8:
           w.Write([]byte("int8!\n" + string(v)))

      //etc, etc
      //more types
      //etc, etc

      case float64:
           w.Write([]byte("float64!\n" + string(v))) //This fails, can't convert, will need something else
      case string:
           w.Write([]byte("string!\n" + v))
      default:
           w.Write([]byte("something else!\n"))
      }
  }

}

但是,是否存在更好的方法来动态检查基础类型并将其转换为可读性呢?我要做的只是吐出查询结果,这好像是我做错了什么。

请注意,即使它的类型明确相同,它也总是会碰到default的情况。

最佳答案

denisekom上的示例使用fmt.Print系列函数将其打印到stdout。使用fmt.Fprint系列函数将示例更改为打印到响应编写器。

fmt.Fprint函数写入指定为第一个参数的io.Writer。响应编写器满足io.Writer接口。这是原始示例中的修改后的代码,其中w是http.ResponseWriter。

vals := make([]interface{}, len(cols))
for i := 0; i < len(cols); i++ {
    vals[i] = new(interface{})
    if i != 0 {
        fmt.Fprint(w, "\t")
    }
    fmt.Fprint(w, cols[i])
}
fmt.Fprintln(w)
for rows.Next() {
    err = rows.Scan(vals...)
    if err != nil {
        fmt.Fprintln(w, err)
        continue
    }
    for i := 0; i < len(vals); i++ {
        if i != 0 {
            fmt.Fprint(w, "\t")
        }
        printValue(w, vals[i].(*interface{}))
    }
    fmt.Fprintln(w)

}

...

func printValue(w io.Writer, pval *interface{}) {
    switch v := (*pval).(type) {
    case nil:
        fmt.Fprint(w, "NULL")
    case bool:
        if v {
            fmt.Fprint(w, "1")
        } else {
            fmt.Fprint(w, "0")
        }
    case []byte:
        fmt.Fprint(w, string(v))
    case time.Time:
        fmt.Fprint(w, v.Format("2006-01-02 15:04:05.999"))
    default:
        fmt.Fprint(w, v)
    }
}

关于问题中的代码:string(v)表达式是字符串转换。字符串转换不会像代码所假定的那样将数字转换为十进制表示形式。有关字符串转换的详细信息,请参见spec。使用上面的fmt包或strconv包将数字转换为十进制字符串。类型开关应为switch v := (*(vals[i].(*interface{})).(type) {。有点混乱,这引出了我的下一个观点。

原始示例使用了比所需更多的间接寻址。这是简化的版本,随时可以与响应编写器一起调用:
func exec(w io.Writer, db *sql.DB, cmd string) error {
    rows, err := db.Query(cmd)
    if err != nil {
        return err
    }
    defer rows.Close()
    cols, err := rows.Columns()
    if err != nil {
        return err
    }
    if cols == nil {
        return nil
    }
    vals := make([]interface{}, len(cols))
    args := make([]interface{}, len(cols))
    for i := 0; i < len(cols); i++ {
        args[i] = &vals[i]
        if i != 0 {
            fmt.Fprint(w, "\t")
        }
        fmt.Fprint(w, cols[i])
    }
    for rows.Next() {
        err = rows.Scan(args...)
        if err != nil {
            fmt.Fprintln(w, err)
            continue
        }
        for i := 0; i < len(vals); i++ {
            if i != 0 {
                fmt.Print("\t")
            }
            printValue(w, vals[i])
        }
        fmt.Fprintln(w)

    }
    if rows.Err() != nil {
        return rows.Err()
    }
    return nil
}

func printValue(w io.Writer, v interface{}) {
    switch v := v.(type) {
    case nil:
        fmt.Fprint(w, "NULL")
    case bool:
        if v {
            fmt.Fprint(w, "1")
        } else {
            fmt.Fprint(w, "0")
        }
    case []byte:
        fmt.Fprint(w, string(v))
    case time.Time:
        fmt.Fprint(w, v.Format("2006-01-02 15:04:05.999"))
    default:
        fmt.Fprint(w, v)
    }
}

关于go - http.ResponseWriter.Write with interface {},我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47662614/

10-14 03:05