ハマったところ
CLIで特定の画像をbinary化してから画像にしてPostで送信する、というコードを書こうと思った時にポインタ型の初期化についてハマったのでメモ。
ざっくり書きたかったコードは以下(※ コードは適当)
func UploadImgFile() error { // 画像を開く f, _ := os.Open("imagePath") // form-dataを入れるバイナリを箱を用意 buf := new(bytes.Buffer) // 箱は multipart型にする w := multipart.NewWriter(buf) // form-dataを作成する ff, _ := w.CreateFormFile("filedName", "test.png") // io.Copyでform-dataにOpenで取得した画像を書き込む if _ , err := io.Copy(ff, f); err != nil { panic(err) } w.Close() // upload処理hogehoge client := http.Client{} req, _ := http.NewRequest("POST", "Upload先のURL", buf) resp, _ := client.Do(req) }
cf. multipart - The Go Programming Language
こういった処理を書こうと思った時の以下の箇所
// form-dataを入れるバイナリを箱を用意 buf := new(bytes.Buffer) // 箱は multipart型にする w := multipart.NewWriter(buf)
ここでのbytes.Bufferの初期化方法についてハマりました。
multipart型でWriterを初期化可能なパターン > The Go Playground
Writer初期化時点でpanicが起きるパターン > The Go Playground
panicになってしまうかどうかはぬるぽを踏んでしまうかどうか、という1点に尽きるのですが、panicになるケースにおいては ポインタ型の変数領域だけ宣言しても、初期値のままなんでゼロ値でポインタ型なのでnilになる
panicにならないケースについては newで領域確保してそのポインタを返しているのでnilでないのでうまくいく
multipart - The Go Programming Language
を見ると引数に指定するのは io.Writer
。しかし、io.Writer
が実装されているのはポインタ型に対してなので、引数に渡すべき butes.Buffer
はポインタ型でなければなりません。
cf. src/bytes/buffer.go - The Go Programming Language
そのため、varで単に初期化した場合でもアドレス型にして渡してあげればコンパイルエラーは起きず、処理を続けることが可能です。> The Go Playground
まとめ
golangのvarによる初期化についてはたまに思いっきりはまってしまうことが多いのでdocument読み返しながら進めないと思わぬ所で時間を食ってしまうなー。