2017-12-05 1 views
0

denisenkomのサンプルを使用してSQLクエリを実行していますが、http.ResponseWriterと組み合わせて、interface{}タイプ変換に苦しんでいます。私がやっていることに近いいくつかの記事がありますが、解決策は重い手のように思えますが、常にfmt(私は使用していません)を使用します。http.ResponseWriter.Write with interface {}

私のクエリは動作し、結果を返します。私はその結果を表示しようとしています。

私のコードは比較的近いと思いますが、うまくいきません。私はいくつかのことを試しましたが、コンパイルさえしません。

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ケースに当たることに注意してください。

答えて

0

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)は文字列変換です。文字列変換は、コードが想定しているように、数値を10進表現に変換しません。文字列変換の詳細については、specを参照してください。上記のようにfmtパッケージまたはstrconvパッケージを使用して、数値を10進数の文字列に変換します。タイプスイッチは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) 
    } 
}