[インデックス 11505] ファイルの概要
このコミットは、Go言語の標準ライブラリであるnet
パッケージにおけるエラー変数の命名規則を統一するためのリファクタリングです。具体的には、エラーを示す変数名として使用されていたe
やerrno
を、よりGo言語の慣習に沿ったerr
に置き換える変更が広範囲にわたって適用されています。
コミット
commit 28397befabea2bb984b8eda963d9e7c16ffafd45
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Wed Feb 1 00:36:45 2012 +0900
net: replace error variable name e, errno with err
R=rsc, r
CC=golang-dev
https://golang.org/cl/5593046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/28397befabea2bb984b8eda963d9e7c16ffafd45
元コミット内容
net: replace error variable name e, errno with err
このコミットの目的は、net
パッケージ内で使用されているエラー変数の名前をe
やerrno
からerr
に統一することです。
変更の背景
Go言語では、関数がエラーを返す場合、慣習的に最後の戻り値としてerror
型を返し、その変数名にはerr
を使用することが推奨されています。これはGoコミュニティ全体で広く受け入れられているスタイルガイドの一部であり、コードの可読性と一貫性を高めることを目的としています。
このコミットが行われた2012年2月は、Go言語がまだ比較的新しい時期であり、標準ライブラリ内でもコーディングスタイルや命名規則の統一が進められていた段階でした。net
パッケージはネットワーク関連の非常に重要な機能を提供する部分であり、そのコードベース全体で一貫したエラーハンドリングの慣習を適用することは、将来的なメンテナンス性や新規開発者のオンボーディングにおいて非常に重要です。
以前はe
やerrno
といった短い変数名が使われていましたが、これらは一般的なエラー変数名であるerr
と比較して、コードを読んだ際に一瞬の判断を要する可能性があります。特に、errno
はC言語のシステムコールでよく使われるエラー番号を指すため、Goのerror
インターフェースとは異なるニュアンスを持つ可能性があり、混乱を招くことも考えられます。このリファクタリングは、このような潜在的な混乱を排除し、Goらしいエラーハンドリングのスタイルを徹底するためのものです。
前提知識の解説
Go言語のエラーハンドリング
Go言語には例外処理の仕組み(try-catchなど)は存在せず、エラーは関数の戻り値として明示的に扱われます。慣習として、エラーを返す可能性のある関数は、最後の戻り値として組み込みのerror
インターフェース型の値を返します。エラーがない場合はnil
を返します。
func doSomething() (result string, err error) {
// ... 処理 ...
if someCondition {
return "", errors.New("something went wrong") // エラーを返す
}
return "success", nil // 成功を返す
}
この際、エラーを受け取る変数名には通常err
が使用されます。
result, err := doSomething()
if err != nil {
// エラー処理
log.Printf("Error: %v", err)
return
}
// 成功時の処理
syscall
パッケージとerrno
Go言語のsyscall
パッケージは、オペレーティングシステムの低レベルなシステムコールへのアクセスを提供します。C言語のシステムコールでは、エラーが発生した場合にグローバル変数errno
にエラーコードが設定されることが一般的です。Goのsyscall
パッケージも、これらのシステムコールをラップする際に、C言語のerrno
に対応するエラー値を返すことがあります。
このコミット以前のコードでは、syscall
パッケージから返されるエラーをerrno
という変数名で受け取っている箇所が見られました。しかし、Goのエラーハンドリングの慣習では、syscall
パッケージから返されるエラーも最終的にはerror
インターフェースとして扱われるため、errno
という変数名はGoのエラーハンドリングの文脈では不自然に映る可能性があります。err
に統一することで、Goのエラーインターフェースとして一貫して扱われることが明確になります。
netFD
構造体とネットワークI/O
Goのnet
パッケージは、ネットワーク通信の基盤を提供します。その内部では、ソケットディスクリプタ(ファイルディスクリプタ)を管理するためのnetFD
という内部構造体が頻繁に登場します。このnetFD
は、ネットワーク接続の読み書き、接続、受け入れ(accept)などの低レベルな操作をカプセル化しています。
このコミットで変更されているファイルの多くは、netFD
に関連するメソッドや、特定のOS(Darwin, FreeBSD, Linux, Windowsなど)に特化したネットワークI/O処理を扱うファイルです。これらのファイルでは、システムコールを直接呼び出す箇所が多く、エラーハンドリングが頻繁に行われます。
技術的詳細
このコミットの技術的な変更は、主に以下の2点に集約されます。
-
エラー変数名の統一:
e
という短い変数名でエラーを受け取っていた箇所をerr
に変更。errno
という変数名でエラーを受け取っていた箇所をerr
に変更。- これにより、コード全体でエラー変数が
err
として一貫して扱われるようになります。
-
関数シグネチャの明示的なエラー戻り値:
- 以前は
func someFunc() (f *Type, err error)
のように、戻り値の変数名が宣言されている場合、return nil, e
のように変数名を省略してe
を返しても、Goコンパイラは自動的にe
をerr
に割り当てていました(名前付き戻り値の機能)。 - しかし、このコミットでは、
return nil, e
のような箇所をreturn nil, err
と明示的に変更しています。これは、変数名の変更に伴う自然な流れですが、より明示的なコード記述を促進する側面もあります。 - また、一部の関数では、戻り値の型宣言が
func someFunc() (err error)
のように変数名を含んでいたものを、func someFunc() error
のように変数名を省略する変更も含まれています。これは、戻り値が単一のエラーである場合に、より簡潔な記述を好むGoのスタイルに合わせたものです。
- 以前は
これらの変更は、Goのgofmt
のような自動フォーマッタでは検出・修正されない種類の変更であり、開発者が手動でコードベース全体をレビューし、Goの慣習に沿って修正する必要があります。このコミットは、Go標準ライブラリの品質と一貫性を高めるための、地道ながらも重要な作業の一環と言えます。
コアとなるコードの変更箇所
変更は多岐にわたりますが、src/pkg/net/fd.go
のnewFD
関数における変更が典型的な例です。
変更前:
func newFD(fd, family, sotype int, net string) (f *netFD, err error) {
onceStartServer.Do(startServer)
if e := syscall.SetNonblock(fd, true); e != nil {
return nil, e
}
f = &netFD{
sysfd: fd,
family: family,
sotype: sotype,
net: net,
}
f.cr = make(chan bool, 1)
f.cw = make(chan bool, 1)
return f, nil
}
変更後:
func newFD(fd, family, sotype int, net string) (*netFD, error) {
onceStartServer.Do(startServer)
if err := syscall.SetNonblock(fd, true); err != nil {
return nil, err
}
netfd := &netFD{
sysfd: fd,
family: family,
sotype: sotype,
net: net,
}
netfd.cr = make(chan bool, 1)
netfd.cw = make(chan bool, 1)
return netfd, nil
}
コアとなるコードの解説
上記のnewFD
関数の変更は、このコミットの意図を明確に示しています。
-
if e := syscall.SetNonblock(fd, true); e != nil { return nil, e }
- ここで
syscall.SetNonblock
が返すエラーを変数e
に代入し、そのe
がnil
でない場合にエラー処理を行っています。 - 変更後には、この
e
がerr
に置き換えられています。 if err := ...; err != nil
というパターンは、Go言語でエラーハンドリングを行う際の最も一般的で推奨されるイディオムです。
- ここで
-
func newFD(...) (f *netFD, err error)
からfunc newFD(...) (*netFD, error)
への変更- 変更前は、戻り値の変数名
f
とerr
が明示的に宣言されていました(名前付き戻り値)。 - 変更後では、戻り値の型のみが指定され、変数名は省略されています。これは、関数内で
netfd
という新しいローカル変数を宣言し、それを明示的にreturn netfd, nil
として返すスタイルに合わせたものです。Goでは、戻り値の変数名が自明である場合や、関数が短い場合に、このように変数名を省略することがよくあります。
- 変更前は、戻り値の変数名
この変更は、機能的な振る舞いを一切変えることなく、コードのスタイルと一貫性を向上させる純粋なリファクタリングです。これにより、Go言語の標準ライブラリがよりGoらしい慣習に沿ったものとなり、開発者にとって読みやすく、理解しやすいコードベースが維持されます。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/doc/
- Go Wiki: Error Handling: https://go.dev/wiki/ErrorHandling
- Go Code Review Comments: Error Handling: https://go.dev/wiki/CodeReviewComments#error-handling
- Go言語の
net
パッケージ: https://pkg.go.dev/net - Go言語の
syscall
パッケージ: https://pkg.go.dev/syscall
参考にした情報源リンク
- Go言語の公式ドキュメントおよびGo Wiki
- Go言語のソースコード(特に
net
パッケージ) - Goコミュニティにおける一般的なコーディング慣習とスタイルガイド
- Gitのコミット履歴と差分表示
- Go言語におけるエラーハンドリングに関する一般的な知識
syscall
パッケージの動作に関する知識- ネットワークプログラミングの基礎知識