IT ニュース&コラム 2019/ 9/23 通巻797号 技術版 ソフトウェアデザイン館 Sage Plaisir 21  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ■■ Go 言語でよく defer される Close 関数のエラーを捕まえる ■■ Go言語では、例外処理の finally 節に相当する機能として defer ステートメント があります。 関数をコールするコードの直前に defer を書くと、すぐにその関数を 呼び出すのではなく、実行中の関数から返るときにその関数を呼び出します。 この機能によって確実に close 関数などの終了処理を行うことができます。 たとえば、以下のような defer を使わない関数定義があるとします。 func NotDeferredCall() error { file, err := os.Open( fileName ); if err != nil { return err } buffer, err := io.ReadAll( file ); if err != nil { return err } err := file.Close(); if err != nil { return err } return nil } 上記の関数を defer を使うように変えると下記のようになります。 func DeferredCall() error { file, err := os.Open( fileName ); if err != nil { return err } defer file.Close() buffer, err := io.ReadAll( file ); if err != nil { return err } return nil } NotDeferredCall 関数と DeferredCall 関数は、ほとんど同じ動きをしますが 少し違います。 NotDeferredCall 関数では ReadAll 関数でエラーが発生したときに Close 関数が呼ばれないのに対し、DeferredCall 関数では ReadAll 関数でエラーが 発生したときでも Close 関数が呼ばれるところです。 後者のほうが適切ですね。 一般的な Go言語の解説では、ここで説明が終わりますが、実は後者でも問題があり ます。 その問題とは、Close 関数の返り値の err をエラーチェックしなくなった ことです。 Go 言語では panic(例外処理)を使わないことを推奨していますが、 その分、エラーチェックが漏れる可能性が増えています。 それが良いか悪いか というのは面白い議論ですが、悪いという結論だったとしても Go言語はそういう 欠点のある言語として使わざるをえないでしょう。 defer ステートメントに指定した関数の返り値を取得する方法はありません。 では、どうすればいいかというと、無名関数を定義して defer で呼び出し、 間接的に Close 関数を呼び出すことで Close 関数の返り値を捕まえるのです。 func TrueDeferredCall() (err error) { file, err := os.Open( fileName ); if err != nil { return err } defer func() { setNewError( file.Close(), &err ); }() buffer, err := io.ReadAll( file ); if err != nil { return err } return nil } func setNewError( newErr error, currentErr *error ) { if *currentErr == nil { *currentErr = new Err } } 上記の Close 関数の返り値は、setNewError 関数の第1引数に渡ります。 setNewError 関数の第2引数には &err(TrueDeferredCall 関数の名前付き 返り値である err 変数のアドレス)を渡します。 第2引数をこうすることで、 TrueDeferredCall 関数の中で return した値が setNewError 関数に渡る だけでなく、setNewError 関数から返ったときには setNewError 関数の中で 変更された err 変数の値が TrueDeferredCall 関数の返り値になります。 setNewError 関数の中は、すでにエラーが発生していたら何も処理をせず、 まだエラーが発生しないで新しいエラーが発生したら、そのエラーを 出力するという処理をしています。 こうすることで、根本原因に関する エラーが出力されます。 その理由については別の機会に話します。 ややこしい説明になりましたが、要するに Close の返り値のエラーも、 TrueDeferredCall 関数からきちんと返るようになったということです。 参考 Defer, Panic, and Recover - The Go Blog https://blog.golang.org/defer-panic-and-recover ■■ 注目ニュース 一覧 ■■ ◇ IT産業はタダ働きのエンジニアに依存しすぎている。 https://gigazine.net/news/20190918-internet-relies-on-working-for-free/ … 大企業ほど寄付をしない。 ◇ グーグルのAR版 保存ボタンで世界中にデジタルメモを残せる。 https://japan.cnet.com/article/35142640/ … 場所は任意で見る角度に応じて付箋が貼れたらいいと思う ◇ アマゾン、自社製品を優位にするため検索アルゴリズムを変更か。 https://japan.cnet.com/article/35142718/ … していると言うわけがない。 ECサイト一社だけ検索するのはよくない。 ◇ たった2回のタップでクソリプを撃退する機能が日本Twitterでも開始。 https://gigazine.net/news/20190920-twitter-reply-control/ https://japan.cnet.com/article/35142941/ … 即ブロよりは良い機能。より良いユーザーに改心するきっかけになる。 ◇ iPhone 11 シリーズ発表、トリプルカメラ搭載のPro含む3機種。9月20日発売。 https://japan.cnet.com/article/35142486/ … Pro以上で望遠レンズが追加。 ◇ 世界中で命を救いまくる Apple Watchの新モデルとなる Apple Watch Series 5 が登場。 https://gigazine.net/news/20190911-apple-watch-series-5/ … 表示したまま18時間もつ。 ◇ 次世代規格 Wi-Fi 6 の認定プログラムが開始。 https://japan.cnet.com/article/35142726/ … Wi-Fi 6 で高速化と遅延削減。 ◇ 海賊版の個人的なダウンロードは合法とする著作権法改正案がスイスで可決。 https://gigazine.net/news/20190920-swiss-copyright-law-downloading-legal/ … アップロードは禁止。 ◇ Facebook本社で飛び降り自殺が発生。 https://gigazine.net/news/20190920-facebook-headquarter-suicide/ … なぜ自殺したのだろうか。 ◇ ZOZO前澤氏「どうしても宇宙に行きたい」涙ながらに語った退任への思い。 https://japan.cnet.com/article/35142623/ … ゾゾスーツがダサいと批判されて自信を失ったか。 ■■ ソフトウェアデザイン館 Sage Plaisir 21 ■■ ホームページ >>> http://www.sage-p.com/ メルマガ >>> http://www.mag2.com/m/0000083983.html ブログ >>> http://blog.livedoor.jp/sage_p/ ツイッター >>> http://twitter.com/Ts_Neko ダウンロード >>> http://www.sage-p.com/freesoft.htm サポート掲示板 >>> http://www.sage-p.com/kg_ban09/z6037C8.cgi 東日本大震災 >>> http://www.sage-p.com/saigai.html メール >>> ts-neko◇sage-p.com ←◇を@に変えてください 緊急メールは件名に「うどんメール」を付けてください。 このメルマガの登録・解除 - http://www.mag2.com/m/0000083983.htm