[インデックス 11525] ファイルの概要
このコミットは、Go言語の標準ライブラリ net
パッケージから、InvalidConnError
および UnknownSocketError
という2つのエラー型を削除するものです。これらの型は未使用であり、ドキュメント化されておらず、特に InvalidConnError
はGoのエラーハンドリングのイディオムに沿っていないと判断されました。
コミット
commit d3285f2a796f4fc856da9a15ca8a7dbff418aea1
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Tue Jan 31 15:04:42 2012 -0800
net: remove types InvalidConnError and UnknownSocketError
Both are unused and undocumented.
InvalidConnError is also non-idiomatic: a FooError type can
typically describe something, else it would be an ErrFoo
variable.
R=golang-dev, alex.brainman
CC=golang-dev
https://golang.org/cl/5609045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d3285f2a796f4fc856da9a15ca8a7dbff418aea1
元コミット内容
net: remove types InvalidConnError and UnknownSocketError
Both are unused and undocumented.
InvalidConnError is also non-idiomatic: a FooError type can
typically describe something, else it would be an ErrFoo
variable.
変更の背景
このコミットの主な背景は、Go言語の標準ライブラリ net
パッケージ内に存在していた InvalidConnError
と UnknownSocketError
という2つのエラー型が、以下の理由により不要と判断されたためです。
- 未使用 (Unused): コードベースのどこからも参照されておらず、実際に使用されていない「デッドコード」でした。未使用のコードは、メンテナンスの負担を増やし、コードの理解を妨げ、将来的なバグの原因となる可能性があります。
- 未ドキュメント (Undocumented): これらのエラー型は公式にドキュメント化されていませんでした。ドキュメントがない型は、その存在意義や使用方法が不明瞭であり、ライブラリの利用者にとって混乱を招く可能性があります。
- 非イディオム的 (Non-idiomatic): 特に
InvalidConnError
については、Go言語のエラーハンドリングの慣習(イディオム)に沿っていないと指摘されています。Goでは、特定の状態を表すエラーはErrFoo
のようにErr
プレフィックスを持つ変数として定義されることが一般的です。一方、FooError
のような型は、より複雑なエラー情報(エラーコード、追加データなど)をカプセル化するために使用されます。InvalidConnError
は単に「invalid Conn」という文字列を返すだけであり、カスタムエラー型として定義するほどの複雑性を持っていなかったため、Goのイディオムに反していました。
これらの理由から、コードベースの健全性を保ち、Goのエラーハンドリングのベストプラクティスに準拠するために、これらのエラー型を削除することが決定されました。
前提知識の解説
このコミットを理解するためには、Go言語におけるエラーハンドリングの基本的な考え方とイディオムについて理解しておく必要があります。
Go言語のエラーハンドリングの基本
Go言語では、例外処理の代わりにエラーを「値」として扱います。関数がエラーを返す可能性がある場合、その関数の最後の戻り値として error
型を返します。エラーが発生しなかった場合は nil
を返します。
func doSomething() (result string, err error) {
// ... 処理 ...
if somethingWentWrong {
return "", errors.New("something went wrong") // エラーを返す
}
return "success", nil // 成功時はnilを返す
}
// 呼び出し側
result, err := doSomething()
if err != nil {
// エラー処理
fmt.Println("Error:", err)
return
}
// 成功時の処理
fmt.Println("Success:", result)
この if err != nil
というパターンは、Goのエラーハンドリングの最も基本的な形であり、非常に頻繁に登場します。
error
インターフェース
Goの error
型は、実際には以下のように定義された組み込みのインターフェースです。
type error interface {
Error() string
}
つまり、Error() string
メソッドを持つ任意の型は error
インターフェースを満たし、エラーとして扱うことができます。
イディオム的なエラー型
Goでは、エラーを表現する方法にいくつかのイディオムがあります。
-
シンプルなエラー (
errors.New
またはfmt.Errorf
):errors.New("エラーメッセージ")
: 静的なエラーメッセージを持つシンプルなエラーを作成します。fmt.Errorf("フォーマット文字列 %v", 値)
: フォーマットされたメッセージを持つエラーを作成します。動的な情報を含める場合によく使われます。
-
センチネルエラー (Sentinel Errors):
- 特定の、期待されるエラー条件を示すために、パッケージレベルで定義される事前定義されたエラー変数です。
- 通常、
Err
プレフィックスを付けて命名されます(例:var ErrNotFound = errors.New("item not found")
)。 - これらのエラーは、
errors.Is
関数(Go 1.13以降)を使って比較されます。
var ErrPermissionDenied = errors.New("permission denied") func checkAccess() error { // ... return ErrPermissionDenied } // 呼び出し側 err := checkAccess() if errors.Is(err, ErrPermissionDenied) { fmt.Println("アクセスが拒否されました。") }
-
カスタムエラー型 (Custom Error Types):
- より複雑なエラー情報(エラーコード、タイムスタンプ、特定の詳細データなど)をカプセル化する必要がある場合に、
error
インターフェースを実装する独自のstruct
を定義します。 - このコミットで削除された
InvalidConnError
やUnknownSocketError
は、このカスタムエラー型に該当します。しかし、これらは単に文字列を返すだけであり、追加の情報を保持していなかったため、カスタム型として定義するメリットが薄いと判断されました。
type MyCustomError struct { Code int Message string Op string // 失敗した操作 } func (e *MyCustomError) Error() string { return fmt.Sprintf("operation %s failed with code %d: %s", e.Op, e.Code, e.Message) } func performOperation() error { // ... return &MyCustomError{Code: 500, Message: "internal server error", Op: "performOperation"} } // 呼び出し側 err := performOperation() var myErr *MyCustomError if errors.As(err, &myErr) { // errors.Asを使ってカスタムエラー型に変換 fmt.Printf("カスタムエラー: コード=%d, メッセージ=%s\n", myErr.Code, myErr.Message) }
- より複雑なエラー情報(エラーコード、タイムスタンプ、特定の詳細データなど)をカプセル化する必要がある場合に、
FooError
vs ErrFoo
コミットメッセージで言及されている「FooError
type can typically describe something, else it would be an ErrFoo
variable」という点は、Goのエラーハンドリングにおける重要な慣習です。
-
ErrFoo
(変数): これは、特定の、かつシンプルなエラー条件を示すためのセンチネルエラー(errors.New
で作成される)として使用されます。例えば、io.EOF
やos.ErrNotExist
などがこれに該当します。これらは、エラーが発生した理由が単一かつ明確な場合に用いられます。 -
FooError
(型): これは、エラーが単なる文字列メッセージ以上の情報(エラーコード、発生時刻、関連するデータなど)を保持する必要がある場合に、カスタムエラー型として定義されます。例えば、ネットワークエラーの詳細な情報を持つnet.OpError
などがこれに該当します。
InvalidConnError
は、単に「invalid Conn」というメッセージを返すだけで、追加の情報を何も持っていませんでした。そのため、Goのイディオムに照らし合わせると、カスタムエラー型 InvalidConnError
として定義するのではなく、var ErrInvalidConn = errors.New("invalid Conn")
のようなセンチネルエラー変数 ErrInvalidConn
として定義する方が適切である、という判断がなされたと考えられます。
技術的詳細
このコミットは、Go言語の net
パッケージから InvalidConnError
と UnknownSocketError
という2つのカスタムエラー型を削除することで、コードベースの整理とGoのエラーハンドリングイディオムへの準拠を目的としています。
InvalidConnError
の問題点
InvalidConnError
は src/pkg/net/fd.go
と src/pkg/net/fd_windows.go
の両方に定義されていました。その定義は以下の通りです。
type InvalidConnError struct{}
func (e *InvalidConnError) Error() string { return "invalid Conn" }
func (e *InvalidConnError) Temporary() bool { return false }
func (e *InvalidConnError) Timeout() bool { return false }
この型は、error
インターフェースだけでなく、net
パッケージ内で定義されている Temporary()
と Timeout()
メソッドを持つインターフェース(おそらく net.Error
インターフェース)も実装していました。しかし、コミットメッセージが指摘するように、この型は単に「invalid Conn」という固定文字列を返すだけであり、エラーに関する追加のコンテキストや情報を提供していませんでした。
Goのエラーハンドリングのイディオムでは、このようなシンプルなエラーは通常、errors.New
を使用したセンチネルエラー変数(例: var ErrInvalidConn = errors.New("invalid Conn")
)として表現されます。カスタムエラー型は、エラーがより複雑な状態やデータを持つ場合に予約されるべきです。InvalidConnError
はその要件を満たしていなかったため、非イディオム的と判断されました。
UnknownSocketError
の問題点
UnknownSocketError
は src/pkg/net/sock.go
に定義されていました。その定義は以下の通りです。
type UnknownSocketError struct {
sa syscall.Sockaddr
}
func (e *UnknownSocketError) Error() string {
return "unknown socket address type " + reflect.TypeOf(e.sa).String()
}
このエラー型は syscall.Sockaddr
というフィールドを持っており、エラーメッセージにその型情報を含めることで、InvalidConnError
よりもわずかに動的な情報を提供していました。しかし、コミットメッセージではこの型も「unused and undocumented」とされており、実際にコードベースのどこからも使用されていなかったため、削除の対象となりました。未使用のコードは、たとえそれが潜在的に有用な情報を含んでいたとしても、コードベースの肥大化とメンテナンスコストの増加につながります。
削除の意義
これらのエラー型を削除することの意義は以下の通りです。
- コードベースの簡素化: 未使用のコードを削除することで、コードベースがスリムになり、理解しやすくなります。開発者は、実際に使用されているコードに集中できます。
- メンテナンスコストの削減: 未使用のコードは、将来的にバグの原因となったり、依存関係の更新時に問題を引き起こしたりする可能性があります。これらを削除することで、長期的なメンテナンスコストを削減できます。
- イディオムへの準拠:
InvalidConnError
の削除は、Goのエラーハンドリングのベストプラクティスとイディオムへの準拠を強化します。これにより、Goのコードベース全体の一貫性が向上し、新しい開発者がコードを理解しやすくなります。 - ドキュメントの整合性: 未ドキュメントの型を削除することで、ドキュメントと実際のコードベースとの間に不整合が生じる可能性がなくなります。
このコミットは、Go言語の標準ライブラリが常にクリーンで、効率的で、イディオムに沿ったものであることを保証するための継続的な努力の一環と言えます。
コアとなるコードの変更箇所
このコミットでは、以下の3つのファイルから合計21行のコードが削除されています。
-
src/pkg/net/fd.go
:InvalidConnError
型の定義とそのメソッド(Error()
,Temporary()
,Timeout()
)が削除されました。
--- a/src/pkg/net/fd.go +++ b/src/pkg/net/fd.go @@ -43,12 +43,6 @@ type netFD struct { ncr, ncw int } -type InvalidConnError struct{} - -func (e *InvalidConnError) Error() string { return "invalid Conn" } -func (e *InvalidConnError) Temporary() bool { return false } -func (e *e.InvalidConnError) Timeout() bool { return false } - // A pollServer helps FDs determine when to retry a non-blocking // read or write after they get EAGAIN. When an FD needs to wait, // send the fd on s.cr (for a read) or s.cw (for a write) to pass the
-
src/pkg/net/fd_windows.go
:fd.go
と同様に、Windows固有のファイルからもInvalidConnError
型の定義とそのメソッドが削除されました。
--- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -14,12 +14,6 @@ import ( "unsafe" ) -type InvalidConnError struct{} - -func (e *InvalidConnError) Error() string { return "invalid Conn" } -func (e *InvalidConnError) Temporary() bool { return false } -func (e *InvalidConnError) Timeout() bool { return false } - var initErr error func init() {
-
src/pkg/net/sock.go
:UnknownSocketError
型の定義とそのメソッド(Error()
)が削除されました。- また、
UnknownSocketError
の定義で使用されていたreflect
パッケージのインポートも不要になったため削除されました。
--- a/src/pkg/net/sock.go +++ b/src/pkg/net/sock.go @@ -10,7 +10,6 @@ package net import ( "io" - "reflect" "syscall" ) @@ -70,14 +69,6 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal return fd, nil } -type UnknownSocketError struct { - sa syscall.Sockaddr -} - -func (e *UnknownSocketError) Error() string { - return "unknown socket address type " + reflect.TypeOf(e.sa).String() -} - type writerOnly struct { io.Writer }
コアとなるコードの解説
このコミットのコアとなる変更は、Goの net
パッケージから特定のカスタムエラー型を削除することです。
InvalidConnError
の削除
InvalidConnError
は、net
パッケージ内の fd.go
と fd_windows.go
の両方に定義されていました。これは、ネットワーク接続が不正な状態であることを示すために意図されたエラー型でした。しかし、その実装は非常にシンプルで、Error()
メソッドは常に "invalid Conn"
という固定文字列を返すだけでした。また、Temporary()
と Timeout()
メソッドも常に false
を返していました。
Goのエラーハンドリングの慣習では、このように追加情報を持たないシンプルなエラーは、通常、errors.New
を使って定義されるパッケージレベルの変数(センチネルエラー)として扱われます。例えば、var ErrInvalidConn = errors.New("invalid Conn")
のように定義されるべきでした。カスタムエラー型として定義する意味が薄く、Goのイディオムに沿っていなかったため、削除されました。これにより、コードベースの冗長性が減り、Goのエラーハンドリングのベストプラクティスに準拠する形になりました。
UnknownSocketError
の削除
UnknownSocketError
は net/sock.go
に定義されていました。このエラー型は、syscall.Sockaddr
というソケットアドレスの情報を保持し、Error()
メソッドでその型情報をエラーメッセージに含めることで、より詳細な情報を提供しようとしていました。
しかし、コミットメッセージが明確に述べているように、この型は「未使用 (unused)」でした。つまり、このエラー型が実際にどこかのコードで生成されたり、チェックされたりすることはなかったということです。未使用のコードは、コードベースの肥大化を招き、開発者がコードを理解する際のノイズとなります。また、UnknownSocketError
の定義のために reflect
パッケージがインポートされていましたが、この型が削除されたことで reflect
のインポートも不要となり、依存関係が一つ減りました。
変更の全体的な影響
これらのエラー型が削除されたことによる、net
パッケージの外部からの動作上の影響はほとんどありません。なぜなら、これらの型は元々「未使用」であり、外部に公開されていても実際に利用されることがなかったためです。
この変更は、Goの標準ライブラリの内部的な品質向上と、Go言語のエラーハンドリングの設計思想へのより厳密な準拠を目的としています。未使用のコードを削除し、イディオムに沿わない設計を修正することで、コードベースの健全性が保たれ、将来的な開発とメンテナンスが容易になります。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/d3285f2a796f4fc856da9a15ca8a7dbff418aea1
- Go Code Review (CL): https://golang.org/cl/5609045
参考にした情報源リンク
- Go error handling best practices idiomatic error types (Web Search Results)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHEWX3wxTnB0Wxxup5HtxoG4lg1KqijSO6Uf2wPYVgPhRN993ydf35Mllf-DFwWNq-jAA44_A8T3HXfKyykqyXTNyO6_wQ00S3HpAUyNE5lulG7LGJ1Cgt0l8X6joaPeuymwRTo3E-escqlZApMDd5a1yleviPZQ_Wz6Sm_jAh7cCFxqPyjc_iFwmuT6jmfspXEVNE=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEWOgArtk47hAL_LbBhY2cTU2outbhQk45w9LwDfu2XCisU7S2rkYfbXmmOfmNbHbrCruFqkzFrcssJR5OW6IPsLtPSPGQTbuAHyb-CNfyKGgfRHcGWqy3Vf81WSn9sVxLM6Pt-aZHJM3sWEs7rQpjor3WTZ3x3ZVPabErOrQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEUotrrm_wcuWsgBqqIhRWs6UD1OLM_3qf_pyG3qVt2dUsbHzVbovFwLUiD-qYwDSzxHKq0yqOh1ktcz6q0DzscQVcplS3DHKrU0MrMqrrvxgVMF4KDWjrumg==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFqnMmRyitUb3Z1rV0xnAWUZBu9sBFtp1EBbhnMyjnJIsIlhL03XSJklNoWqsg68tgeiS0zCN7rEuXhBmOnYeNTNLbKkhlqVrkPUGs_woHCYSzF-qeIbMxoc2hzdH_P0L8rgg==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHFJwhhw3kRZ2IUaFUHZEHMk7DBRgawXD8--hY6mNMPagtSsbq6ayXRoEiVVCPEr3PTjIqezcqgd3PxztjMnJTXsAMYhI_B1Fe-63kEhLh9U6UBCBvS
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGwe5xCicKqjkG1oQgOotnW-P4Ht5tjUXL7JQTIxdF6Pu3ORzu86oJwaxknSVXXDN7ADDFdiCWcp7jUm78-tErD83jt7q1lIE1llNcGMqQSKucvmZZysHYpX73QyDecUbBW5A6QayVNMEeaPAb9CAe3rDXWkG39BISNCllgQV_UZh6LXaeywG6qUwdI
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHy6ybG92rkQRGMUKrr46XFa8Ar0XH3AJO_5qzvlhNfyoSrYrAbsTqxKdtVaeT3IDRIcPDcebvQjt_voelOdKmeShHXcDuZCsCPVSilbKGwMjM--C6v3X345DTVo6O9ww7ykrGMC0FNX91yd0C11X7fbIad4tYsD8DDu0c8aU44WwYGXCOQtWaF0MCaAKw=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHoSGDaPlvL1drjrsUIQy18Fb4W_kPpARuF92OFM3AtommM1kq7ma85urC1KQpDaYWoVy3lgokFnHNuft24jep8HadkggBxnIYbRdoDDNdr788xfaw6CS08ksr_4GNhHcQPepGxieeCj2TzYgRrsu-QWeXGcA4iYi6CcRM=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHK4U8nNTX83vu6MQND7fzbT1PQAMZNEN2HqYEcT3yKmFDfYYM1bIy-YNCZWeSKZ2imDlQDdmpSV-LoNxK5UmvipA4PyLOqu-wbOyQa5UgdMwHx_p-ypUDRgIp79VmdeMPcpx3K4MiKIyca78Po7zJbFfHI5G_RBfU9FPh7BXLaqTZlI2_st6b7QgCd-uZiCLFiFcSBzLC7i4
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH3_Pf0Qd6zmV7VxDvPGeBy203eKUFqkO6TwwRtmfpxFRVFf3tWd-lWphXccWY49b9AAlO-Cg_DJ_bab5iiGjbsW3lKiSE-4gjvq8W3H0hEcPz5guNJF2if7DBi8KOhL0cOB_AZGzd-WVEqCncLHGZ8g2_M77iGRBzzE7NVXSQqqEQ3f1OkfgO-W-r8u7kYu4CK
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEW05fV74HnmqMq-VftPSn9gRqpxcoLwNoXhRRr_Isr5qa_HswNKNOJN1S60lh1i1fe6zSdbnAeZnVOGG0xHrqY_c1siqrFlsAUDAJZx-iUIVieRm1O0Bq6QQdBVVE7D60W57_bvW1i477uIoq5MG3e0Q==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHxyk_iIoI2PliC1mOs7tO3SD3Wxh9IzhxKKtBMwd5OV8pvSvLMag2hk1HK-j-IUlOBafj8ffOXb2dyu-t3Y0x77c95wDDNqUj9Lceg5wm4CTBYMKT3yGrG8SxWZ-lzra9z2LY-okOXWFTH0Ty0
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGVy67JHSPUGWbhSoaU_wBTozQR30e79hnEZUu0jRZguGeb1kNjcLXMLN4RMGVii9vLihRzesXGyI6fJbQnYy93F7-jR6QwXJ7ZZcQUhNc2zRWWDcPktEMD-V9gR9rQw7ZkQY_6s4X0N5A67KaLfkTRJO4F5L_jlzw=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEa4U00vumLYdT4hjMKlquerukSQQtFgh10O5XVm5LB6AXyVG-KCDAwLuuzbvHT2LEQu2dV_ax2sXXKYGNkh33v7mLCuhAd6eeFLjCzz-Wiee7kAn9W7Xj21l7Y1Q==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFU-_ujBOmp6ztmX0vD9ODtK_435iygFTlUorpmjGSmpNjd005qb0AtAKKwkSe_InW4NdCS7PjD06yg7MUF_eQhy1Mwbmx8JLZVppGSMF2Lbed8zJk_36pk81HX4pN49gCTJXo=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEN_YPt-B2vXdupC83kkf1P_A0hGhGdS-W4hkkaTe_P_36byfkoP4pSTNqQkzSe5VghEZawjJd-U-8KYG5TYtcEqr4u68RsvOuW3wnVevOkYAIO2xb1MKHUVQqBrdoxk9j5VweIOzUayfBt5-B_2IDPZBJZndj-h02mhpk6G1yI7WE8f0j0VIfHI5G_RBfU9FPh7BXLaqTZlI2_st6b7QgCd-uZiCLFiFcSBzLC7i4
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE8kCzS-uNkapzSJiW78HiNZweu43uWGw2Xvs2_XVP1-mhHPPcmmyPTAYua5wUl7eQ1iPt7ta3VgmCaAoZE1t-zzs0vVfYAeP8j6k5jb4wP_b05_KLs37kp7baIRSt0No-MusOR16ALtTz9TwBkZU98sBnWWOVKDJXSabx11NHQsUjCFCrOLO26
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH5m09kfQy7cyjQ8zILraiNHp2bimeBvrLY-MIzAtuo6gw7pwaesFOPGpSIdyCIgHSd5cG7yPEda7Xs328Fhn-DnBpn177wta64o9yTkcJa0yB1e3CgHT-G1_ubrXhY5a5eAYEyC3Ur4tnRoK8VRQE4deluO96Gvn_wHR-MJy2uLBYP99AWXlL1BfEVCGzhhsUaJNwp9HOu
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH__OAyy8uF6NrG0QuK037eB-b9iW7pUgyTANWNVDez0fBWDjsa7vI4WzWWrV3NsPHwrlMvBGWPSLTAR3XhdBNLE_tv_fabYn7r0gV81n8qafQJ8-g_QE3n_B_LLcZ6lmQ=