[インデックス 19052] ファイルの概要
このコミットは、Go言語の標準ライブラリであるnet
パッケージ内のエラーメッセージから、一貫性のない「net:」プレフィックスを削除することを目的としています。これにより、エラーメッセージの統一性が向上し、特にnet.OpError
型と組み合わせて使用する際のエラーハンドリングがより明確になります。
コミット
net: remove "net:" prefix from error messages
The prefix was not uniformly applied and is probably better
left off for using with OpError.
Update #4856
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/84660046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3f5288cb0845a8e9d5c3e6ec73141876d4179f9e
元コミット内容
commit 3f5288cb0845a8e9d5c3e6ec73141876d4179f9e
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Tue Apr 8 06:14:19 2014 +0900
net: remove "net:" prefix from error messages
The prefix was not uniformly applied and is probably better
left off for using with OpError.
Update #4856
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/84660046
---
src/pkg/net/interface.go | 10 +++++-----\n src/pkg/net/ipsock_plan9.go | 4 ++--\n src/pkg/net/lookup_plan9.go | 4 ++--\n 3 files changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index 0713e9cd6a..2e9f1ebc67 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -7,11 +7,11 @@ package net
import "errors"
var (
-\terrInvalidInterface = errors.New("net: invalid interface")
-\terrInvalidInterfaceIndex = errors.New("net: invalid interface index")
-\terrInvalidInterfaceName = errors.New("net: invalid interface name")
-\terrNoSuchInterface = errors.New("net: no such interface")
-\terrNoSuchMulticastInterface = errors.New("net: no such multicast interface")
+\terrInvalidInterface = errors.New("invalid network interface")
+\terrInvalidInterfaceIndex = errors.New("invalid network interface index")
+\terrInvalidInterfaceName = errors.New("invalid network interface name")
+\terrNoSuchInterface = errors.New("no such network interface")
+\terrNoSuchMulticastInterface = errors.New("no such multicast network interface")
)
// Interface represents a mapping between network interface name
diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
index 914ed50826..94ceea31b0 100644
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -60,12 +60,12 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
\tif i >= 0 {\n \t\taddr = ParseIP(s[:i])\n \t\tif addr == nil {\n-\t\t\treturn nil, 0, errors.New("net: parsing IP failed")
+\t\t\treturn nil, 0, errors.New("parsing IP failed")
\t\t}\n \t}\n \tp, _, ok := dtoi(s[i+1:], 0)\n \tif !ok {\n-\t\treturn nil, 0, errors.New("net: parsing port failed")
+\t\treturn nil, 0, errors.New("parsing port failed")
\t}\n \tif p < 0 || p > 0xFFFF {\n \t\treturn nil, 0, &AddrError{"invalid port", string(p)}\ndiff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
index 2ccd997c2c..b80ac10e0d 100644
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -63,7 +63,7 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
\t}\n \tf := getFields(lines[0])\n \tif len(f) < 2 {\n-\t\treturn "", "", errors.New("net: bad response from ndb/cs")
+\t\treturn "", "", errors.New("bad response from ndb/cs")
\t}\n \tclone, dest = f[0], f[1]\n \treturn\n@@ -199,7 +199,7 @@ func lookupCNAME(name string) (cname string, err error) {\n \t\t\treturn f[2] + ".", nil\n \t\t}\n \t}\n-\treturn "", errors.New("net: bad response from ndb/dns")
+\treturn "", errors.New("bad response from ndb/dns")
}\n \n func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {\n```
## 変更の背景
このコミットの主な背景は、Go言語の`net`パッケージ内で生成されるエラーメッセージの**一貫性の欠如**と、`net.OpError`型との**より良い連携**です。
コミットメッセージに「The prefix was not uniformly applied」とあるように、`net`パッケージ内の全てのエラーメッセージが「net:」というプレフィックスを付けていたわけではありませんでした。このような不統一は、エラーメッセージをプログラムで解析したり、ユーザーがエラーを理解したりする際に混乱を招く可能性があります。
さらに重要なのは、「is probably better left off for using with OpError」という記述です。`net.OpError`は、ネットワーク操作に関する詳細な情報(操作の種類、ネットワークの種類、ソース/宛先アドレス、根本的なエラーなど)を提供する構造化されたエラー型です。エラーが`net.OpError`にラップされる場合、`OpError`自体が既にそのエラーがネットワーク関連のものであることを示しています。この状況で、内部のエラーメッセージにさらに「net:」というプレフィックスが付いていると、情報が冗長になり、場合によっては解析を複雑にする可能性があります。
例えば、`net.OpError`は`Op`フィールドに「read」や「dial」といった操作名を、`Net`フィールドに「tcp」や「udp」といったネットワークタイプを保持します。もし根本的なエラーが「net: parsing IP failed」であった場合、`OpError`の構造と組み合わせると「read tcp 127.0.0.1:80: net: parsing IP failed」のようになり、`net:`が重複して見えます。プレフィックスを削除することで、より簡潔で情報が重複しないエラーメッセージが期待されます。
コミットメッセージには「Update #4856」とありますが、検索結果によるとGoのIssue #4856は「add support for TCP Fast Open」という全く異なる内容でした。これはコミットメッセージの記述ミスである可能性が高いです。このコミットの意図は、エラーメッセージの改善と`OpError`との整合性向上に焦点を当てていると考えるのが妥当です。
## 前提知識の解説
### Go言語のエラーハンドリング
Go言語では、エラーは`error`インターフェースによって表現されます。これは非常にシンプルなインターフェースで、`Error() string`という単一のメソッドを持ち、エラーの文字列表現を返します。
* **`errors.New(msg string)`**: 最も基本的なエラーの作成方法です。指定された文字列をエラーメッセージとして持つ新しいエラーを返します。このコミットで変更されているのは、この`errors.New`に渡される文字列です。
* **カスタムエラー型**: より詳細なエラー情報を提供するために、開発者は独自の構造体を`error`インターフェースを実装するように定義できます。これにより、エラーの種類に応じて異なる情報を保持し、タイプアサーション(`if err, ok := err.(*MyErrorType); ok { ... }`)を使ってエラーの具体的な型をチェックし、そのフィールドにアクセスすることができます。
### `net`パッケージ
`net`パッケージは、Go言語でネットワークI/Oを扱うための基本的な機能を提供します。TCP/UDP接続、IPアドレスの解決、ネットワークインターフェース情報の取得など、様々なネットワーク関連の操作が含まれます。
### `net.OpError`
`net.OpError`は、`net`パッケージが返す特定のエラー型です。これは、ネットワーク操作中に発生したエラーに関する豊富なコンテキストを提供するために設計されています。`net.OpError`構造体は以下のフィールドを持ちます。
* **`Op` (string)**: エラーが発生したネットワーク操作(例: "read", "write", "dial", "listen")。
* **`Net` (string)**: 操作が行われたネットワークの種類(例: "tcp", "udp", "tcp4", "ip")。
* **`Source` (`net.Addr`)**: 操作のローカルアドレス(該当する場合)。
* **`Addr` (`net.Addr`)**: 操作のリモートアドレス(該当する場合)。
* **`Err` (error)**: 根本的な、より具体的なエラー(例: `os.SyscallError`, `net.DNSError`)。
`net.OpError`は、`error`インターフェースだけでなく、`net.Error`インターフェースも実装しています。`net.Error`インターフェースは`Timeout() bool`と`Temporary() bool`メソッドを提供し、エラーがタイムアウトによるものか、一時的なものかを示すことができます(ただし、`Temporary()`はGoのバージョンによっては非推奨とされています)。
この`net.OpError`の存在により、エラーメッセージの先頭に「net:」というプレフィックスを付ける必要性が薄れます。なぜなら、エラーが`net.OpError`型であること自体が、そのエラーがネットワーク関連のものであることを明確に示しているからです。これにより、エラーメッセージはより簡潔になり、`OpError`の構造化された情報と組み合わせて利用する際に、より効果的になります。
## 技術的詳細
このコミットの技術的な変更は、非常にシンプルでありながら、Goのエラーハンドリングのベストプラクティスに沿ったものです。
Goのエラーメッセージは、通常、ユーザーや開発者が問題を診断するために読みやすいものであるべきです。しかし、プログラムによるエラーの解析を容易にするために、エラーメッセージの構造や内容にはある程度の予測可能性が求められます。
`net`パッケージ内で「net:」というプレフィックスが不均一に適用されていたことは、以下のような問題を引き起こす可能性がありました。
1. **一貫性の欠如**: 一部のエラーにはプレフィックスがあり、他のエラーにはないという状況は、エラーメッセージの生成ロジックに一貫性がないことを示唆します。これはコードの品質や保守性に影響を与える可能性があります。
2. **冗長性**: `net.OpError`のような構造化されたエラー型が導入されたことで、エラーがネットワーク関連であるという情報は既に`OpError`の型情報やフィールド(`Op`, `Net`など)によって提供されます。この状況で、根本的なエラーメッセージにも「net:」というプレフィックスが含まれていると、情報が重複し、冗長になります。
3. **解析の複雑化**: エラーメッセージの先頭に特定のプレフィックスがあるかないかで挙動が変わる場合、エラーを文字列として解析する際に余分なロジックが必要になります。プレフィックスを削除し、`net.OpError`のような構造化されたエラー型に依存することで、エラーの分類や処理がより堅牢になります。開発者は文字列解析に頼るのではなく、型アサーションによってエラーの型を特定し、そのフィールドにアクセスすることで、より信頼性の高いエラーハンドリングを実装できます。
この変更は、エラーメッセージの文字列自体から冗長な情報を削除し、代わりにGoの型システムと`net.OpError`の構造を利用して、エラーのコンテキストをより効果的に伝えるという設計思想を反映しています。これにより、エラーメッセージはよりクリーンになり、プログラムによるエラー処理が容易になります。
## コアとなるコードの変更箇所
このコミットでは、以下の3つのファイルが変更されています。
1. `src/pkg/net/interface.go`
2. `src/pkg/net/ipsock_plan9.go`
3. `src/pkg/net/lookup_plan9.go`
それぞれのファイルで、`errors.New()`関数に渡される文字列リテラルから「net: 」というプレフィックスが削除されています。
**`src/pkg/net/interface.go` の変更例:**
```diff
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -7,11 +7,11 @@ package net
import "errors"
var (
- errInvalidInterface = errors.New("net: invalid interface")
- errInvalidInterfaceIndex = errors.New("net: invalid interface index")
- errInvalidInterfaceName = errors.New("net: invalid interface name")
- errNoSuchInterface = errors.New("net: no such interface")
- errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
+ errInvalidInterface = errors.New("invalid network interface")
+ errInvalidInterfaceIndex = errors.New("invalid network interface index")
+ errInvalidInterfaceName = errors.New("invalid network interface name")
+ errNoSuchInterface = errors.New("no such network interface")
+ errNoSuchMulticastInterface = errors.New("no such multicast network interface")
)
src/pkg/net/ipsock_plan9.go
の変更例:
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -60,12 +60,12 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
if i >= 0 {
addr = ParseIP(s[:i])
if addr == nil {
- return nil, 0, errors.New("net: parsing IP failed")
+ return nil, 0, errors.New("parsing IP failed")
}
}
p, _, ok := dtoi(s[i+1:], 0)
if !ok {
- return nil, 0, errors.New("net: parsing port failed")
+ return nil, 0, errors.New("parsing port failed")
}
if p < 0 || p > 0xFFFF {
return nil, 0, &AddrError{"invalid port", string(p)}
src/pkg/net/lookup_plan9.go
の変更例:
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -63,7 +63,7 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
}
f := getFields(lines[0])
if len(f) < 2 {
- return "", "", errors.New("net: bad response from ndb/cs")
+ return "", "", errors.New("bad response from ndb/cs")
}
clone, dest = f[0], f[1]
return
@@ -199,7 +199,7 @@ func lookupCNAME(name string) (cname string, err error) {
return f[2] + ".", nil
}
}
- return "", errors.New("net: bad response from ndb/dns")
+ return "", errors.New("bad response from ndb/dns")
}
コアとなるコードの解説
変更された各ファイルは、Goのnet
パッケージの一部であり、それぞれ異なるネットワーク関連の機能を提供しています。
src/pkg/net/interface.go
: ネットワークインターフェースに関する情報(名前、インデックス、IPアドレスなど)を扱うための定数エラーを定義しています。これらのエラーは、無効なインターフェースが指定された場合などに返されます。src/pkg/net/ipsock_plan9.go
: Plan 9オペレーティングシステム向けのIPソケットアドレスの解析ロジックを含んでいます。IPアドレスやポートの解析に失敗した場合にエラーを返します。src/pkg/net/lookup_plan9.go
: Plan 9向けのDNSルックアップ機能を含んでいます。ネームサーバーからの応答が不正な場合などにエラーを返します。
これらのファイルで行われた変更は、すべてerrors.New("net: ...")
という形式でエラーを生成している箇所から「net: 」というプレフィックスを削除するという共通のパターンに従っています。
この変更の意図は、前述の「変更の背景」と「技術的詳細」で述べた通り、エラーメッセージの冗長性を排除し、net.OpError
のような構造化されたエラー型との整合性を高めることにあります。
例えば、interface.go
のerrInvalidInterface
は、以前は"net: invalid interface"
でしたが、変更後は"invalid network interface"
となりました。もしこのエラーがnet.OpError
にラップされて返される場合、OpError
のNet
フィールドが「ip」や「tcp」といったネットワークタイプを示し、Op
フィールドが「interface lookup」のような操作を示すことで、エラーがネットワークインターフェースに関連するものであることが明確に伝わります。この状況で、根本的なエラーメッセージにさらに「net:」というプレフィックスが含まれていると、情報が重複し、エラーメッセージが不必要に長くなります。
このコミットは、Goのエラーハンドリングの進化の一環として、エラーメッセージの品質とプログラムによるエラー処理の効率性を向上させるための、細部への配慮を示しています。
関連リンク
- Go CL 84660046: https://golang.org/cl/84660046
- Go
net
パッケージドキュメント: https://pkg.go.dev/net - Go
net.OpError
ドキュメント: https://pkg.go.dev/net#OpError
参考にした情報源リンク
- Go
net.OpError
の解説 (go.dev): https://go.dev/blog/go1.1-network-errors (これはGo 1.1でのnet.OpError
の導入に関するブログ記事で、関連する情報源として非常に有用です。) - Go
errors
パッケージドキュメント: https://pkg.go.dev/errors - Go issue #4856 (TCP Fast Open): https://github.com/golang/go/issues/4856 (コミットメッセージに記載がありますが、本コミットの内容とは直接関連しないため、参考情報として記載します。)
- Stack Overflow - What is the purpose of net.OpError in Go?: https://stackoverflow.com/questions/24000000/what-is-the-purpose-of-net-operror-in-go
- Airbrake - Go Error Handling: https://airbrake.io/blog/go-error-handling
- JetBrains GoLand Documentation - Error handling: https://www.jetbrains.com/help/go/error-handling.html
- documentation.help - Go net.OpError: https://documentation.help/Go/net.OpError.html
- GitHub - golang/go/src/net/interface.go: https://github.com/golang/go/blob/master/src/net/interface.go
- GitHub - golang/go/src/net/ipsock_plan9.go: https://github.com/golang/go/blob/master/src/net/ipsock_plan9.go
- GitHub - golang/go/src/net/lookup_plan9.go: https://github.com/golang/go/blob/master/src/net/lookup_plan9.go