質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

2回答

1138閲覧

goのエラーハンドリングについて、基礎的な質問。

shrk458

総合スコア20

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2020/06/02 16:59

前提・実現したいこと

Golangのエラーハンドリングの基礎についてです。
httpのリクエストについて勉強しているのですが、以下のようなエラー処理の記述が出てきました。

Go

1file, err := fileHeader.Open() 2 if err == nil { 3 data, err := ioutil.ReadAll(file) 4 if err == nil { 5 fmt.Fprintln(w, string(data)) 6 } 7 }

僕の認識があっているのかわからないので教えていただきたいです。

file, err := fileHeader.Open()について
file := fileHeader.Open()と、この変数のerrを表す。

errは以下の型で示されている。

Go

1type error interface { 2 Error() string 3}

2行目のif err == nilについて
errがnilであるということはfileHeader.Openがnil、つまり中身がない場合を指定しているのでしょうか。

3行目以降のエラー処理について
上記と同様の考え方でよろしいでしょうか。

エラーがどのように処理されているのか考えているうちによくわからなくなっているので、エラー処理の解説をよろしくお願いします。

元のソースコードは以下です。
###ソースコード全体

Go

1package main 2 3import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7) 8 9func process(w http.ResponseWriter, r *http.Request) { 10 r.ParseMultipartForm(1024) 11 fileHeader := r.MultipartForm.File["uploaded"][0] 12 file, err := fileHeader.Open() 13 if err == nil { 14 data, err := ioutil.ReadAll(file) 15 if err == nil { 16 fmt.Fprintln(w, string(data)) 17 } 18 } 19} 20 21func main() { 22 server := http.Server{ 23 Addr: "127.0.0.1:8080", 24 } 25 http.HandleFunc("/process", process) 26 server.ListenAndServe() 27} 28

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

補足ですが、Go では early return (エラーがあった場合に早めに return しちゃう)がよく用いられます。early returnすると見通しが良くなります、ネストも浅くなります。以下の解決にも効果があるかもしれません。

エラーがどのように処理されているのか考えているうちによくわからなくなっているので、エラー処理の解説をよろしくお願いします。

  • process 関数を early return するようにしたコード (+HTTPステータスコードを付与)

go

1func process(w http.ResponseWriter, r *http.Request) { 2 // r.ParseMultipartForm もエラーが起きる場合があるので、エラーをチェックする 3 if err := r.ParseMultipartForm(1024); err != nil { 4 http.Error(w, "something...", http.StatusInternalServerError) 5 return 6 } 7 fileHeader := r.MultipartForm.File["uploaded"][0] 8 file, err := fileHeader.Open() 9 10 // エラーをチェックして、エラーがあれば早めにreturnする 11 // err が nil でないということは何かしらのエラーが発生しているので、エラーをハンドリングする 12 if err != nil { 13 http.Error(w, "something...", http.StatusInternalServerError) 14 return 15 } 16 17 // エラーをチェックして、エラーがあれば早めにreturnする 18 data, err := ioutil.ReadAll(file) 19 if err != nil { 20 http.Error(w, "something...", http.StatusInternalServerError) 21 return 22 } 23 24 // ここではエラーは発生していないので、正常系の処理を実施 25 w.WriteHeader(http.StatusOK) 26 fmt.Fprintln(w, string(data)) 27}

ご参考まで。

投稿2020/06/03 00:52

d_tutuz

総合スコア730

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shrk458

2020/06/03 05:52

丁寧な解説ありがとうございます。 コード内でわかりやすいコメントまでしていただき、とても参考になりました。
guest

0

ベストアンサー

file, err := fileHeader.Open()について
file := fileHeader.Open()と、この変数のerrを表す。

go の関数は、多値と言って複数の値を同時に返すことができます。
参考: 多値と多重代入 | blog.PanicBlanket.com

fileHeader.Open() の場合、fileHeader は multipart パッケージの FileHeader 型 ですね。メソッドの宣言に

func (fh *FileHeader) Open() (File, error)

とありますが、最後の (File, error) が戻り値の型を表していて、この場合は File 型の値と error 型の値を同時に返す (とはいえ、どちらかの値はたぶん nil) ことになります。

2行目のif err == nilについて
errがnilであるということはfileHeader.Openがnil、つまり中身がない場合を指定しているのでしょうか。

go のエラーハンドリングの習慣として、エラーがない場合は err == nil かつ最初の戻り値 (この場合は file) が有効な値で、エラーの場合は err != nil かつ file は多くの場合無効な値となります。
参考: エラー・ハンドリングについて(追記あり) — プログラミング言語 Go | text.Baldanders.info

ちなみに、元のソースコードを見るとエラーの場合には何もしてませんが、http のハンドラとしては何らかのエラーを w に出力すべきかと思います。

投稿2020/06/02 18:43

hoshi-takanori

総合スコア7901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shrk458

2020/06/03 05:27

回答ありがとうございます。 理解が正しいのか不安なので確認したいのですが、 func (fh *FileHeader) Open() (File, error) の戻り値(File, error)が、それぞれ変数file,errに返されるということであっているでしょうか。
shrk458

2020/06/03 15:26

わかりました。 丁寧な解説ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問