Go言語入門:言語仕様 -Vol.146-

スポンサーリンク
Go言語入門:言語仕様 -Vol.146- 用語解説
Go言語入門:言語仕様 -Vol.146-
この記事は約6分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語の言語仕様について解説しています。

スポンサーリンク

背景

Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。

言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。

そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。

言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!

実行時パニック

配列の範囲外へのインデックスアクセスのような実行時エラーは、実装定義のインターフェース型 runtime.Error の値を伴う組み込み関数 panic の呼び出しと同等の、実行時パニックを引き起こします。その型は、事前宣言されたインターフェース型 error を満たします。異なる実行時エラーの状態を表す正確なエラー値は、規定されていません。

package runtime

type Error interface {
	error
	// そしておそらく他のメソッドも
}

解説

結論:配列の範囲外アクセスなど、実行中に起きる致命的なエラーは「パニック」を引き起こす。パニックは panic を呼んだのと同じ状態で、その値は runtime.Error

error の一種)。具体的なエラー値の中身は仕様で固定されていない。

パニックとは

「パニック(panic)」は、Goにおける実行時の異常事態を表す仕組みです。前の節で学んだ error(戻り値で穏やかに返すエラー)とは別物で、こちらはプログラムの実行を即座に中断させる深刻なエラーです。

代表例が、原文に挙げられている配列やスライスの範囲外アクセスです。

a := []int{10, 20, 30} // 要素は3つ(添字 0〜2)
fmt.Println(a[5])      // 添字5は存在しない → 実行時パニック!

存在しない添字 a[5] にアクセスしようとした瞬間、プログラムはパニックを起こします。コンパイル時には気づかれず、実行してその行に到達した瞬間に発生するのがポイントです(だから「実行時=run-time」パニックと呼ばれます)。

火災報知器に例えると、error が「点検で見つけた不具合の報告書」だとすれば、パニックは「火事だ!と非常ベルが鳴って全員退避する」ような、その場で処理を止める緊急事態です。

panic を呼んだのと同等

原文は「panic という組み込み関数を呼んだのと同等」と述べています。panic は自分のコードからも明示的に呼べる関数で、呼ぶとその場で実行が中断されます。

panic("致命的なエラーが発生しました") // 自分でパニックを起こす

範囲外アクセスのような実行時エラーは、Goが内部的にこの panic を呼んでいるのと同じ状態を引き起こす、という意味です。自分で起こそうが、システムが起こそうが、パニックという同じ現象になります。

パニックの値は runtime.Error 型

パニックには「値」が伴います。実行時エラーによるパニックの場合、その値は runtime.Error というインターフェース型です。

package runtime

type Error interface {
	error          // error インターフェースを埋め込んでいる
	// そしておそらく他のメソッドも
}

ここで重要なのは、runtime.Error の定義の中に error が埋め込まれていることです。これは「インターフェースの埋め込み」というGoの仕組みで、runtime.Errorerror が要求するメソッド(Error() string)をすべて含むことを意味します。

つまり、**runtime.Errorerror の一種(error を満たす)**です。前の節で学んだエラー処理の道具が、パニックの値にもそのまま使える、ということです。入れ子の資格に例えると、「error という基本資格」を内包した「runtime.Error という上位資格」のような関係で、上位資格を持つ者は基本資格の条件も当然満たしています。

「正確なエラー値は規定されていない」

原文の “unspecified”(規定されていない)の部分は、初心者には少し分かりにくいので補足します。

これは、「どの実行時エラーがどんな具体的な値になるか」をGo言語仕様としては固定していないという意味です。範囲外アクセスのパニックが、内部的にどんな構造の値を持つかといった詳細は、実装(Goコンパイラやランタイム)に委ねられています。

実用上の教訓は、パニックの値の中身の具体的な型を当てにしたコードを書くべきではないということです。runtime.Error(ひいては error)として扱える、という保証だけに頼るのが安全です。

パニックは recover で受け止められる

範囲外アクセスのようなパニックは、放置すればプログラムを丸ごと終了させてしまいます。ただしGoには、パニックを途中で受け止めて回復する recover という仕組みもあります(この節の範囲外ですが、関連知識として補足します)。

func safeAccess() {
	defer func() {
		if r := recover(); r != nil { // パニックを受け止める
			fmt.Println("パニックから回復:", r)
		}
	}()

	a := []int{1, 2, 3}
	fmt.Println(a[10]) // パニック発生 → 上の recover で捕捉される
}

defer(関数終了時に実行される後始末の予約)の中で recover() を呼ぶと、発生したパニックを捕まえてプログラムの全面停止を防げます。ただしGoの設計思想では、通常の想定内のエラーは error の戻り値で扱い、パニックは本当に異常な事態に限るのが基本です。パニックと recover を例外処理のように常用するのは推奨されません。


補足:パニックを引き起こす代表的な実行時エラーには、範囲外アクセスのほかに、nil ポインタの参照外し(nil なのに中身を取り出そうとする)、0 による整数の除算、型アサーションの失敗などがあります。いずれも「コンパイルは通るが、実行してその状況に至ると初めて落ちる」種類のエラーです。これらを避けるには、添字や nil のチェックを事前に行うのが基本的な防御策になります。

おわりに 

本日は、Go言語の言語仕様について解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました