Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10140] ファイルの概要

このコミットは、Go言語のテストスイートにおけるエラー関連の修正を目的としています。具体的には、test/fixedbugs/bug365.gotest/import.gotest/zerodivide.go の3つのファイルに対して、型チェックやエラーリカバリの挙動に関するバグを修正し、テストの正確性を向上させています。特に、os.Error 型の扱いとゼロ除算エラーのリカバリメカニズムに関する調整が含まれています。

コミット

  • コミットハッシュ: 64f78c918aa690abf790f0fc20acef379ed858f6
  • Author: Russ Cox rsc@golang.org
  • Date: Thu Oct 27 19:41:39 2011 -0700
  • コミットメッセージ:
    test: error-related fixes
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5328051
    

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/64f78c918aa690abf790f0fc20acef379ed858f6

元コミット内容

test: error-related fixes

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5328051

変更の背景

このコミットが行われた2011年10月は、Go言語がまだ比較的新しく、言語仕様や標準ライブラリが活発に開発・改善されていた時期です。特にエラーハンドリングのメカニズムは、Go言語の設計思想の核となる部分であり、その挙動は厳密にテストされる必要がありました。

このコミットの背景には、以下の問題意識があったと考えられます。

  1. 型チェックの厳密化: os.Error のような特定の型が、意図しない形で参照されたり、未定義の型として扱われたりするケースに対するテストの強化。
  2. インポートの挙動の明確化: パッケージのインポート方法(エイリアス、ドットインポートなど)が、型解決にどのように影響するかを正確にテストする必要性。
  3. パニックとリカバリの正確なテスト: Go言語の panicrecover メカニズムは、実行時エラーを捕捉し、プログラムのクラッシュを防ぐための重要な機能です。特にゼロ除算のような実行時パニックが、recover によって正しく捕捉され、期待されるエラー型に変換されるかを検証するテストの修正が必要でした。

これらの修正は、Goコンパイラとランタイムの安定性および正確性を確保し、開発者がGo言語の提供するエラーハンドリングモデルを信頼して利用できるようにするために不可欠でした。

前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念と当時のエラーハンドリングに関する知識が必要です。

Go言語のエラーハンドリング

Go言語では、エラーは error インターフェースによって表現されます。このインターフェースは非常にシンプルで、Error() string というメソッドを一つだけ持ちます。

type error interface {
    Error() string
}

関数は通常、最後の戻り値として error 型を返します。エラーが発生しなかった場合は nil を返し、エラーが発生した場合は nil ではない error 値を返します。開発者はこの戻り値をチェックすることでエラーを処理します。

os.Error (当時の状況)

Go言語の初期には、os パッケージ内に os.Error という型が存在していました。これは、オペレーティングシステム関連のエラーを表すために使われていましたが、後にGo言語の標準的な error インターフェースに統合され、os.Error という具体的な型は使われなくなりました。このコミットが行われた時点では、まだ os.Error が存在していたか、あるいはその移行期にあった可能性があります。コミット内容を見ると、os.Errorerror インターフェースの実装として、あるいは特定の文脈で使われていたことが示唆されます。

panicrecover

Go言語には、例外処理に似た panicrecover というメカニズムがあります。

  • panic: 実行時エラー(例: ゼロ除算、nilポインタ参照)や、回復不能なエラーが発生した場合にプログラムを異常終了させるために使用されます。panic が発生すると、現在の関数の実行が停止し、defer関数が実行されながら呼び出しスタックを遡ります。
  • recover: defer 関数内で呼び出されることで、panic からの回復を試みることができます。recovernil ではない値を返した場合、panic は捕捉され、プログラムの異常終了を防ぐことができます。recover は、予期せぬ実行時エラーを捕捉し、クリーンアップ処理を行ったり、エラーをログに記録したりするのに役立ちます。

このコミットでは、特に test/zerodivide.go において、ゼロ除算による panicrecover によって捕捉され、そのパニック値が runtime.Error 型として扱われることをテストしています。

ドットインポート (import . "os")

Go言語では、import . "os" のようにパッケージをインポートすると、そのパッケージのエクスポートされた識別子(関数、変数、型など)を、パッケージ名をプレフィックスとして付けずに直接参照できるようになります。例えば、os.File ではなく File と書けるようになります。これはコードを簡潔にする一方で、名前の衝突を引き起こす可能性もあります。

技術的詳細

このコミットは、Go言語のテストスイート内の3つのファイルにわたる修正を含んでいます。それぞれのファイルでの変更は、Go言語の型システム、インポートメカニズム、およびエラーハンドリングの正確性を検証するためのものです。

test/fixedbugs/bug365.go

このファイルは、Goコンパイラの型チェックに関する特定のバグ(bug365)をテストするためのものです。

変更前:

type S struct {
	err os.Error  // ERROR "undefined|expected package"
	Num int
}

ここでは os.Error が使われており、コンパイラが「undefined」または「expected package」というエラーを出すことを期待しています。これは、os.Error がこのコンテキストで正しく解決されないことをテストしていると考えられます。

変更後:

type S struct {
	err foo.Bar // ERROR "undefined|expected package"
	Num int
}

os.Errorfoo.Bar という架空の型に置き換えています。これにより、テストの意図がより明確になります。つまり、S 構造体内で未定義の型を参照した場合に、コンパイラが期待通りにエラーを報告するかどうかをテストしています。os.Error が実際に存在するかどうかに依存せず、一般的な未定義型のエラーをテストするようになりました。

test/import.go

このファイルは、Go言語のパッケージインポートの様々な形式と、それらが型解決にどのように影響するかをテストするためのものです。

変更前:

import _os_ "os"
import "os"
import . "os"

func f(e os.Error)

func main() {
	var _e_ _os_.Error
	var dot Error

	f(_e_)
	f(dot)
}

このテストでは、os.Error 型を引数にとる関数 f を定義し、異なるインポート形式で取得した os.Error 型の変数 (_e_dot) をその関数に渡しています。

変更後:

import _os_ "os"
import "os"
import . "os"

func f(e *os.File)

func main() {
	var _e_ *_os_.File
	var dot *File

	f(_e_)
	f(dot)
}

os.Error 型の代わりに *os.File 型を使用するように変更されています。これは、os.Error がGo言語の進化の過程で一般的な error インターフェースに統合されたこと、または os.Error の具体的な型としての利用が推奨されなくなったことに関連している可能性があります。*os.Fileos パッケージの具体的な型であり、インポートの挙動をテストする上でより適切であると判断されたと考えられます。この変更により、_os_.File (エイリアスインポート) と File (ドットインポート) が正しく *os.File 型として解決されることをテストしています。

test/zerodivide.go

このファイルは、ゼロ除算によるパニックと、そのパニックが recover によってどのように捕捉されるかをテストするためのものです。

変更前:

type Error interface {
	String() string
}

// ...

func error(fn func()) (error string) {
	defer func() {
		if e := recover(); e != nil {
			error = e.(Error).String()
		}
	}()
	fn()
}

このコードでは、Error という独自のインターフェースを定義し、recover で捕捉したパニック値をこの Error インターフェースに型アサーションしています。

変更後:

import (
	"fmt"
	"math"
	"runtime" // 追加
	"strings"
)

// ...

func error(fn func()) (error string) {
	defer func() {
		if e := recover(); e != nil {
			error = e.(runtime.Error).String()
		}
	}()
	fn()
}
  • Error という独自のインターフェースの定義が削除されました。
  • runtime パッケージがインポートされました。
  • recover で捕捉したパニック値を e.(Error).String() から e.(runtime.Error).String() に変更しました。

この変更は非常に重要です。Go言語において、ゼロ除算のような実行時パニックは runtime.Error インターフェースを実装する値として発生します。したがって、recover でこれらのパニックを捕捉し、その String() メソッドを呼び出すためには、runtime.Error に型アサーションするのが正しい方法です。独自の Error インターフェースに型アサーションすることは、Goのランタイムが生成するパニック値の実際の型と一致しないため、テストが失敗するか、誤った結果を報告する可能性がありました。この修正により、ゼロ除算パニックのテストがGo言語の実際のランタイム挙動と一致するようになりました。

コアとなるコードの変更箇所

test/fixedbugs/bug365.go

--- a/test/fixedbugs/bug365.go
+++ b/test/fixedbugs/bug365.go
@@ -12,11 +12,11 @@
 package main
 
 type S struct {
-	err os.Error  // ERROR "undefined|expected package"
+	err foo.Bar // ERROR "undefined|expected package"
 	Num int
 }
 
 func main() {
 	s := S{}
-	_ = s.Num  // no error here please
+	_ = s.Num // no error here please
 }

test/import.go

--- a/test/import.go
+++ b/test/import.go
@@ -13,13 +13,12 @@ import _os_ "os"\n import "os"\n import . "os"\n \n-func f(e os.Error)\n+func f(e *os.File)\n \n func main() {\n-\tvar _e_ _os_.Error\n-\tvar dot Error\n+\tvar _e_ *_os_.File\n+\tvar dot *File\n \n \tf(_e_)\n \tf(dot)\n }\n-\n```

### `test/zerodivide.go`
```diff
--- a/test/zerodivide.go
+++ b/test/zerodivide.go
@@ -9,13 +9,10 @@ package main
 import (
 	"fmt"
 	"math"
+	"runtime"
 	"strings"
 )
 
-type Error interface {
-	String() string
-}
-
 type ErrorTest struct {
 	name string
 	fn   func()
@@ -164,7 +161,7 @@ var errorTests = []ErrorTest{\n func error(fn func()) (error string) {\n 	defer func() {\n \t\tif e := recover(); e != nil {\n-\t\t\terror = e.(Error).String()\n+\t\t\terror = e.(runtime.Error).String()\n \t\t}\n \t}()\n \tfn()\n```

## コアとなるコードの解説

### `test/fixedbugs/bug365.go` の変更

-   **変更点**: `S` 構造体の `err` フィールドの型を `os.Error` から `foo.Bar` に変更。
-   **解説**: この変更は、特定のGoコンパイラのバグ(bug365)をテストする際の意図をより明確にするものです。以前は `os.Error` を使っていましたが、これは `os` パッケージに依存するため、テストの汎用性が低かった可能性があります。`foo.Bar` という架空の型を使用することで、コンパイラが未定義の型に対して正しくエラーを報告するかどうかを、より純粋な形でテストできるようになりました。これは、コンパイラの型解決ロジックの正確性を検証するために重要です。

### `test/import.go` の変更

-   **変更点**: 関数 `f` の引数と `main` 関数内の変数の型を `os.Error` から `*os.File` に変更。
-   **解説**: この変更は、Go言語の進化に伴う `os.Error` 型の扱いの変化を反映していると考えられます。`os.Error` は後に一般的な `error` インターフェースに統合されたため、具体的な型としてのテストには不向きになった可能性があります。代わりに `*os.File` という `os` パッケージ内の具体的な型を使用することで、エイリアスインポート (`_os_.File`) やドットインポート (`File`) が正しく機能し、期待される型に解決されることを、より適切にテストできるようになりました。これは、Go言語のパッケージインポートメカニズムの堅牢性を保証するために重要です。

### `test/zerodivide.go` の変更

-   **変更点**:
    1.  独自の `Error` インターフェースの定義を削除。
    2.  `runtime` パッケージをインポート。
    3.  `recover` で捕捉したパニック値の型アサーションを `e.(Error).String()` から `e.(runtime.Error).String()` に変更。
-   **解説**: この変更は、Go言語の `panic` と `recover` メカニズムの正確なテストにとって極めて重要です。Goのランタイムが生成するゼロ除算のようなパニックは、内部的に `runtime.Error` インターフェースを実装する値として発生します。以前のコードでは、独自の `Error` インターフェースに型アサーションしていましたが、これはGoランタイムの実際の挙動と一致しませんでした。`runtime` パッケージをインポートし、`e.(runtime.Error).String()` とすることで、`recover` が捕捉したパニック値が実際に `runtime.Error` 型であることを検証し、その `String()` メソッドを安全に呼び出すことができるようになりました。これにより、Go言語のパニックとリカバリのメカニズムが期待通りに機能することを、より正確にテストできるようになります。

## 関連リンク

-   Go CL 5328051: [https://golang.org/cl/5328051](https://golang.org/cl/5328051)

## 参考にした情報源リンク

-   Go's approach to error handling has evolved since its inception, but the core concept of `error` as an interface remains central. The `os.Error` type specifically refers to errors originating from operating system operations.
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEvi2xMiPfNowVBq8_dVx7O2h_qrJmgIhxFlFQPoZ0USscIMfdixq5NdM3mCpvZ7XpxuqcVSHhwruz2ZNEzM9GyzYPTsR0DOB8HaDHr2fQ6ozPZdvtnu8Xt1ceE1dfUvYoH3Ek2](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEvi2xMiPfNowVBq8_dVx7O2h_qrJmgIhxFlFQPoZ0USscIMfdixq5NdM3mCpvZ7XpxuqcVSHhwruz2ZNEzM9GyzYPTsR0DOB8HaDHr2fQ6ozPZdvtnu8Xt1ceE1dfUvYoH3Ek2)
-   Go's `error` interface: `type error interface { Error() string }`
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFezyyTa8SG4s17Ml5iY04xtXNjw6CwZ2Fg7jLxhR2gG5bhbeAXbTXZ70x4-zLEbF5mtsyK-wRsOfdsS23GuFw81d8LYgSYUppoXwrQYPLOcAytDHI1Jyn8QJXs_5CwnWElIRsj-9w8yN5dp_rIO3p5xKBU6ruFknpEdDUOb1chfVxgY6cogCebn_Ag](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFezyyTa8SG4s17Ml5iY04xtXNjw6CwZ2Fg7jLxhR2gG5bhbeAXbTXZ70x4-zLEbF5iY04xtXNjw6CwZ2Fg7jLxhR2gG5bhbeAXbTXZ70x4-zLEbF5mtsyK-wRsOfdsS23GuFw81d8LYgSYUppoXwrQYPLOcAytDHI1Jyn8QJXs_5CwnWElIRsj-9w8yN5dp_rIO3p5xKBU6ruFknpEdDUOb1chfVxgY6cogCebn_Ag)
-   `os.Open` and `error` values:
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHBE8PSVnybdqtvoD_RaVpErymCK_zxjPM6DhcsScK7HXR5VLuBNWjPMSV4HqDmuippDKdCi5_Oe3uSz1FVtRsYXQikAiekK0PB9pQLUoncZw==](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHBE8PSVnybdqtvoD_RaVpErymCK_zxjPM6DhcsScK7HXR5VLuBNWjPMSV4HqDmuippDKdCi5_Oe3uSz1FVtRsYXQikAiekK0PB9pQLUoncZw==)
-   Pre-Go 1.13 Error Handling and Go 1.13 and Beyond (Error Wrapping):
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFEfBIWkDPfMjwa867WwHX4maGK_vgoXv1AbTP2a2YehZMk2g1a8GRUWkvgAxyODcMTrdATsYEts8FiRVEBi6tYtV5HsQAd1CDult2pcFwC-KLkX8-pFfDQfWnA_5FEyc_tzClv55O4Qzpjj2QTOBAUwGXG4rZGi-l6Ny2yumZYheY-X1YmexixO6Hlj4a-o0BGgjUyrLnI](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFEfBIWkDPfMjwa867WwHX4maGK_vgoXv1AbTP2a2YehZMk2g1a8GRUWkvgAxyODcMTrdATsYEts8FiRVEBi6tYtV5HsQAd1CDult2pcFwC-KLkX8-pFfDQfWnA_5FEyc_tzClv55O4Qzpjj2QTOBAUwGXG4rZGi-l6Ny2yumZYheY-X1YmexixO6Hlj4a-o0BGgjUyrLnI)
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGaSxonY_W1ZmOYu-UVwy-9pfeellzNcqQTBzb_luzw1g4zDXSJ4qOxOBKXiITet9C5s6r1Kw4ZlRm9RECB6mJeiXC8X0rsSdxPFIQq2wuBfR1G9898llvjT0AF6AMoPaahINj6bDc9-ABtSrTwxGzqdZAX7zPEIALNCcLONmwWNJ7QVPNQ0j2TX3t2lUjQ](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGaSxonY_W1ZmOYu-UVwy-9pfeellzNcqQTBzb_luzw1g4zDXSJ4qOxOBKXiITet9C5s6r1Kw4ZlRm9RECB6mJeiXC8X0rsSdxPFIQq2wuBfR1G9898llvjT0AF6AMoPaahINj6bDc9-ABtSrTwxGzqdZAX7zPEIALNCcLONmwWNJ7QVPNQ0j2TX3t2lUjQ)
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHYSrWp4KflFznK3_p_WMO7ygkf8aJkIqNJscALlFmo8luIsVrQlF38Kr6JTfIgHKKQTkI2C259f5u4UuZfEht__2AiZIqQbooeQ4fRvBE7k6W4yNWQvHHVpaebAU_FCWvvA_kklUzvFCmSr4z0efuIc2mLg18kW0PcLOrS_PJUFDCCRg==](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHYSrWp4KflFznK3_p_WMO7ygkf8aJkIqNJscALlFmo8luIsVrQlF38Kr6JTfIgHKKQTkI2C259f5u4UuZfEht__2AiZIqQbooeQ4fRvBE7k6W4yNWQvHHVpaebAU_FCWvvA_kklUzvFCmSr4z0efuIc2mLg18kW0PcLOrS_PJUFDCCRg==)
    -   [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE4zFyNSHJo91cE8twl-Gz3LRF1XPLK0wElAJlUhkXlyetVPy0rLRivyW-jmCfQKDAIDyfnB2GDSs_V7jsAX6D89o6l_pQN0mo99SgAurJOe0zD0BNV_3304zod2RP_Ex0Nrz4XcxEaq3Udgwwf-238c0kTbrXOgc0rnZ9yeyR2pQM=](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE4zFyNSHJo91cE8twl-Gz3LRF1XPLK0wElAJlUhkXlyetVPy0rLRivyW-jmCfQKDAIDyfnB2GDSs_V7jsAX6D89o6l_pQN0mo99SgAurJOe0zD0BNV_3304zod2RP_Ex0Nrz4XcxEaq3Udgwwf-238c0kTbrXOgc0rnZ9yeyR2pQM=)