[インデックス 1400] ファイルの概要
コミット
このコミットは、Go言語の初期開発段階(2008年12月)において、go
ステートメントがインターフェースのメソッドを呼び出す際の挙動に関するバグをテストするために追加されたものです。具体的には、インターフェース型変数を介してメソッドをゴルーチンとして実行しようとした際に発生していたコンパイラまたはランタイムのエラーを捕捉するためのテストケース test/bugs/bug130.go
を追加しています。このテストは、当時のGoコンパイラが go i.send(c)
のようなコードを正しく処理できないことを示しており、test/golden.out
に記録されたエラーメッセージ fatal error: getoutarg: not a func RANGE
がその証拠です。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d
元コミット内容
commit 3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d
Author: Ian Lance Taylor <iant@golang.org>
Date: Tue Dec 30 15:03:46 2008 -0800
Test for a go statement which calls a method on an interface.
R=ken
DELTA=20 (20 added, 0 deleted, 0 changed)
OCL=21889
CL=21929
---\n test/bugs/bug130.go | 20 ++++++++++++++++++++\n test/golden.out | 4 ++++\n 2 files changed, 24 insertions(+)
diff --git a/test/bugs/bug130.go b/test/bugs/bug130.go
new file mode 100644
index 0000000000..6e189ca5ce
--- /dev/null
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+ s := S{0};
+ var i I = &s;
+ c := new(chan int);
+ go i.send(c);
+ sys.exit(<-c);
+}
diff --git a/test/golden.out b/test/golden.out
index feb0a4566e..50b957f121 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly: 6g bugs/bug125.go
bugs/bug129.go:6: syscall is package, not var
BUG129
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
=========== fixedbugs/bug016.go
fixedbugs/bug016.go:7: overflow converting constant to uint
変更の背景
このコミットは、Go言語の初期開発におけるバグ修正プロセスの一環として行われました。Go言語は、その設計当初から並行処理(コンカレンシー)を言語の核となる機能として重視しており、go
ステートメントとチャネルはその主要な要素です。また、インターフェースはGoのポリモーフィズムを実現するための重要な機能です。
このコミットが追加された2008年当時、Go言語はまだ公開されておらず、活発な開発が行われていました。新しい言語機能が実装される過程では、予期せぬバグやエッジケースが頻繁に発見されます。特に、go
ステートメントとインターフェースのメソッド呼び出しという、Goの重要な二つの概念が組み合わさる場面では、コンパイラやランタイムが正しくコードを生成・実行できない可能性がありました。
test/bugs/bug130.go
は、まさにそのような問題、すなわち「インターフェースのメソッドをゴルーチンとして起動する」という特定のコードパターンが、当時のGoコンパイラ(またはランタイム)によって正しく処理されないことを示すために作成されました。test/golden.out
に記録された fatal error: getoutarg: not a func RANGE
というエラーは、コンパイラの内部的な問題、おそらくは関数呼び出しの引数処理や、ゴルーチン起動時のコンテキスト生成に関するバグを示唆しています。このテストの追加は、このバグを特定し、将来的に修正されたことを確認するための重要なステップでした。
前提知識の解説
Go言語の並行処理(Concurrency)
Go言語の最も特徴的な機能の一つが、軽量な並行処理のサポートです。
- ゴルーチン (Goroutines): Goにおける並行実行の単位です。OSのスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行することが可能です。
go
キーワードを関数の前に置くことで、その関数を新しいゴルーチンとして実行します。 例:go myFunction()
- チャネル (Channels): ゴルーチン間の安全な通信を可能にするための「パイプ」のようなものです。チャネルを通じて値を送受信することで、共有メモリによる競合状態(race condition)を避けることができます。
例:
c := make(chan int)
(チャネルの作成),c <- value
(送信),value := <-c
(受信)
Go言語のインターフェース (Interfaces)
Goのインターフェースは、オブジェクト指向プログラミングにおけるポリモーフィズムを実現するための強力なメカニズムです。
- 暗黙的な実装: Goのインターフェースは、JavaやC#のように
implements
キーワードを使って明示的に実装を宣言する必要がありません。ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを「暗黙的に」実装しているとみなされます。 - メソッドセット: インターフェースはメソッドのシグネチャ(名前、引数、戻り値)の集合を定義します。型がそのインターフェースを実装していると見なされるためには、その型のメソッドセットがインターフェースのメソッドセットを「含む」必要があります。
- 動的ディスパッチ: インターフェース型変数に具体的な型の値を代入すると、そのインターフェースを介したメソッド呼び出しは、実行時にその具体的な型のメソッドが呼び出されます(動的ディスパッチ)。
fatal error: getoutarg: not a func RANGE
このエラーメッセージは、Goコンパイラの非常に低レベルな部分で発生する内部エラーを示しています。
getoutarg
: これはGoコンパイラの内部関数名である可能性が高いです。関数呼び出しの引数(outarg
は "output argument" または "outgoing argument" の略かもしれません)を処理する部分に関連していると推測されます。not a func RANGE
:RANGE
はコンパイラがコードの特定の範囲(例えば、関数の本体やループの範囲)を処理する際に使用する内部的な概念かもしれません。not a func RANGE
は、コンパイラが関数呼び出しのコンテキストで期待される「関数の範囲」を正しく識別できなかった、あるいは処理できなかったことを示唆しています。
このエラーは、特にインターフェースを介したメソッド呼び出しをゴルーチンとして起動する際に、コンパイラがその動的な性質を正しく解決し、ゴルーチン起動に必要なコード(スタックフレームの準備、引数の渡し方など)を生成できなかったために発生したと考えられます。これは、Go言語の初期段階におけるコンパイラの成熟度や、特定の複雑なコードパスの処理におけるバグを示しています。
技術的詳細
このコミットが追加した test/bugs/bug130.go
は、以下のGo言語の機能の組み合わせをテストしています。
- インターフェースの定義:
type I interface { send(chan <- int) }
I
というインターフェースを定義し、send
というメソッドを持つことを規定しています。send
メソッドはchan <- int
型のチャネルを引数にとり、何も返しません。chan <- int
は「int型を送信専用のチャネル」であることを示します。 - 構造体とメソッドの実装:
type S struct { v int } func (p *S) send(c chan <- int) { c <- p.v }
S
という構造体を定義し、そのポインタレシーバを持つsend
メソッドを実装しています。このsend
メソッドは、S
型のv
フィールドの値を引数c
のチャネルに送信します。これにより、*S
型は暗黙的にI
インターフェースを実装します。 - インターフェース型変数への代入:
var i I = &s;
main
関数内でS
型の変数s
を作成し、そのアドレス&s
をI
インターフェース型の変数i
に代入しています。これにより、i
は*S
型の具体的な値を保持し、I
インターフェースで定義されたsend
メソッドを呼び出すことができます。 - チャネルの作成:
c := new(chan int);
int
型の値を送受信するためのチャネルを作成しています。 - インターフェースメソッドのゴルーチン起動:
go i.send(c);
これがこのテストの核心部分です。インターフェース型変数i
を介して、そのメソッドsend
を新しいゴルーチンとして起動しようとしています。
当時のGoコンパイラは、この go i.send(c)
という構文を正しく処理できませんでした。インターフェースメソッドの呼び出しは、実行時に具体的な型が決定される動的ディスパッチを伴います。これを go
ステートメントと組み合わせることで、コンパイラはゴルーチン起動時に必要なコンテキスト(どの具体的なメソッドを呼び出すか、その引数は何かなど)を正しく構築できなかったと考えられます。
test/golden.out
に記録された fatal error: getoutarg: not a func RANGE
は、この問題がコンパイラのバックエンド、特に関数呼び出しの引数処理や、コードの実行範囲(RANGE
)の解析に関連する部分で発生していたことを示唆しています。これは、コンパイラがインターフェースメソッドの動的ディスパッチとゴルーチン起動のメカニズムを統合する際に直面した初期の課題の一つであり、このテストケースは、そのバグを再現し、将来の修正を検証するための重要なリファレンスとなりました。
コアとなるコードの変更箇所
このコミットのコアとなる変更は、新しいテストファイル test/bugs/bug130.go
の追加です。
--- a/test/bugs/bug130.go
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+ s := S{0};
+ var i I = &s;
+ c := new(chan int);
+ go i.send(c);
+ sys.exit(<-c);
+}
そして、このテストが失敗することを期待して、test/golden.out
にそのエラーメッセージを追加しています。
--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly: 6g bugs/bug125.go
bugs/bug129.go:6: syscall is package, not var
BUG129
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
=========== fixedbugs/bug016.go
fixedbugs/bug016.go:7: overflow converting constant to uint
コアとなるコードの解説
test/bugs/bug130.go
は、Go言語のコンパイラまたはランタイムにおける特定のバグを再現するための最小限のコードです。
-
インターフェース
I
の定義:type I interface { send(chan <- int) }
これは、send
という名前のメソッドを持つインターフェースを定義しています。このメソッドはint
型の値を送信するためのチャネルを引数にとります。 -
構造体
S
とそのメソッドsend
の実装:type S struct { v int } func (p *S) send(c chan <- int) { c <- p.v }
S
は単一の整数フィールドv
を持つシンプルな構造体です。*S
型に定義されたsend
メソッドは、I
インターフェースのsend
メソッドのシグネチャと一致するため、*S
型は暗黙的にI
インターフェースを実装します。このメソッドは、レシーバp
のv
の値を引数で渡されたチャネルc
に送信します。 -
main
関数内のロジック:func main() { s := S{0}; var i I = &s; c := new(chan int); go i.send(c); sys.exit(<-c); }
s := S{0};
:S
型の変数s
を初期値0
で宣言・初期化します。var i I = &s;
:I
インターフェース型の変数i
を宣言し、s
のアドレス(*S
型)を代入します。これにより、i
はS
のインスタンスをインターフェースとして参照します。c := new(chan int);
:int
型のチャネルc
を作成します。go i.send(c);
: この行がテストの核心です。 インターフェース型変数i
を介して、そのsend
メソッドを新しいゴルーチンとして起動しようとしています。当時のGoコンパイラは、この動的なメソッドディスパッチを伴うゴルーチン起動を正しく処理できず、内部エラーfatal error: getoutarg: not a func RANGE
を発生させていました。sys.exit(<-c);
:main
ゴルーチンは、c
チャネルから値を受信するまでブロックします。もしgo i.send(c)
が成功していれば、send
ゴルーチンが0
をチャネルに送信し、main
ゴルーチンは0
を受け取って正常終了するはずです。しかし、バグによりゴルーチンが起動しないため、この行は実行されず、コンパイル時または実行時にエラーが発生します。
test/golden.out
の変更は、このテストが期待通りに失敗し、特定のエラーメッセージを出力することを確認するためのものです。これは、テスト駆動開発(TDD)のアプローチに似ており、まずバグを再現するテストを作成し、そのテストが失敗することを確認してから、バグ修正に取り掛かるという流れを示唆しています。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Go言語の並行処理に関する公式ブログ記事: https://go.dev/blog/concurrency-is-not-parallelism
- Go言語のインターフェースに関する公式ブログ記事: https://go.dev/blog/interfaces
参考にした情報源リンク
- Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
- Go言語の初期のメーリングリストやバグトラッカー(当時の情報源は公開されていない可能性が高いですが、コミットメッセージの
OCL
やCL
番号は内部的な変更リスト番号を示唆しています) - Go言語のコンパイラ設計に関する一般的な情報(Goのコンパイラは、初期にはC言語で書かれ、後にGo自身で書き直されました。このコミットの時期はC言語版コンパイラの時代です。)
[インデックス 1400] ファイルの概要
コミット
このコミットは、Go言語の初期開発段階(2008年12月)において、go
ステートメントがインターフェースのメソッドを呼び出す際の挙動に関するバグをテストするために追加されたものです。具体的には、インターフェース型変数を介してメソッドをゴルーチンとして実行しようとした際に発生していたコンパイラまたはランタイムのエラーを捕捉するためのテストケース test/bugs/bug130.go
を追加しています。このテストは、当時のGoコンパイラが go i.send(c)
のようなコードを正しく処理できないことを示しており、test/golden.out
に記録されたエラーメッセージ fatal error: getoutarg: not a func RANGE
がその証拠です。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d
元コミット内容
commit 3f69acfb0c638f2f96cb21c2b5f8374e5cb6040d
Author: Ian Lance Taylor <iant@golang.org>
Date: Tue Dec 30 15:03:46 2008 -0800
Test for a go statement which calls a method on an interface.
R=ken
DELTA=20 (20 added, 0 deleted, 0 changed)
OCL=21889
CL=21929
---\n test/bugs/bug130.go | 20 ++++++++++++++++++++\n test/golden.out | 4 ++++\n 2 files changed, 24 insertions(+)
diff --git a/test/bugs/bug130.go b/test/bugs/bug130.go
new file mode 100644
index 0000000000..6e189ca5ce
--- /dev/null
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+ s := S{0};
+ var i I = &s;
+ c := new(chan int);
+ go i.send(c);
+ sys.exit(<-c);
+}
diff --git a/test/golden.out b/test/golden.out
index feb0a4566e..50b957f121 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly: 6g bugs/bug125.go
bugs/bug129.go:6: syscall is package, not var
BUG129
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
=========== fixedbugs/bug016.go
fixedbugs/bug016.go:7: overflow converting constant to uint
変更の背景
このコミットは、Go言語の初期開発におけるバグ修正プロセスの一環として行われました。Go言語は、その設計当初から並行処理(コンカレンシー)を言語の核となる機能として重視しており、go
ステートメントとチャネルはその主要な要素です。また、インターフェースはGoのポリモーフィズムを実現するための重要な機能です。
このコミットが追加された2008年当時、Go言語はまだ公開されておらず、活発な開発が行われていました。新しい言語機能が実装される過程では、予期せぬバグやエッジケースが頻繁に発見されます。特に、go
ステートメントとインターフェースのメソッド呼び出しという、Goの重要な二つの概念が組み合わさる場面では、コンパイラやランタイムが正しくコードを生成・実行できない可能性がありました。
test/bugs/bug130.go
は、まさにそのような問題、すなわち「インターフェースのメソッドをゴルーチンとして起動する」という特定のコードパターンが、当時のGoコンパイラ(またはランタイム)によって正しく処理されないことを示すために作成されました。test/golden.out
に記録された fatal error: getoutarg: not a func RANGE
というエラーは、コンパイラの内部的な問題、おそらくは関数呼び出しの引数処理や、ゴルーチン起動時のコンテキスト生成に関するバグを示唆しています。このテストの追加は、このバグを特定し、将来的に修正されたことを確認するための重要なステップでした。
前提知識の解説
Go言語の並行処理(Concurrency)
Go言語の最も特徴的な機能の一つが、軽量な並行処理のサポートです。
- ゴルーチン (Goroutines): Goにおける並行実行の単位です。OSのスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行することが可能です。
go
キーワードを関数の前に置くことで、その関数を新しいゴルーチンとして実行します。 例:go myFunction()
- チャネル (Channels): ゴルーチン間の安全な通信を可能にするための「パイプ」のようなものです。チャネルを通じて値を送受信することで、共有メモリによる競合状態(race condition)を避けることができます。
例:
c := make(chan int)
(チャネルの作成),c <- value
(送信),value := <-c
(受信)
Go言語のインターフェース (Interfaces)
Goのインターフェースは、オブジェクト指向プログラミングにおけるポリモーフィズムを実現するための強力なメカニズムです。
- 暗黙的な実装: Goのインターフェースは、JavaやC#のように
implements
キーワードを使って明示的に実装を宣言する必要がありません。ある型がインターフェースで定義されたすべてのメソッドを実装していれば、その型はそのインターフェースを「暗黙的に」実装しているとみなされます。 - メソッドセット: インターフェースはメソッドのシグネチャ(名前、引数、戻り値)の集合を定義します。型がそのインターフェースを実装していると見なされるためには、その型のメソッドセットがインターフェースのメソッドセットを「含む」必要があります。
- 動的ディスパッチ: インターフェース型変数に具体的な型の値を代入すると、そのインターフェースを介したメソッド呼び出しは、実行時にその具体的な型のメソッドが呼び出されます(動的ディスパッチ)。
fatal error: getoutarg: not a func RANGE
このエラーメッセージは、Goコンパイラの非常に低レベルな部分で発生する内部エラーを示しています。Web検索の結果によると、このエラーは2009年頃のGo言語の初期バージョンで報告された内部コンパイラエラーであり、関数引数または範囲式の処理におけるコンパイラの問題を示していました。これはユーザーが書いたコードのエラーではなく、Goコンパイラ自体のバグであり、その後のGoツールチェーンのアップデートで解決されたはずです。
getoutarg
: これはGoコンパイラの内部関数名である可能性が高いです。関数呼び出しの引数(outarg
は "output argument" または "outgoing argument" の略かもしれません)を処理する部分に関連していると推測されます。not a func RANGE
:RANGE
はコンパイラがコードの特定の範囲(例えば、関数の本体やループの範囲)を処理する際に使用する内部的な概念かもしれません。not a func RANGE
は、コンパイラが関数呼び出しのコンテキストで期待される「関数の範囲」を正しく識別できなかった、あるいは処理できなかったことを示唆しています。
このエラーは、特にインターフェースを介したメソッド呼び出しをゴルーチンとして起動する際に、コンパイラがその動的な性質を正しく解決し、ゴルーチン起動に必要なコード(スタックフレームの準備、引数の渡し方など)を生成できなかったために発生したと考えられます。これは、Go言語の初期段階におけるコンパイラの成熟度や、特定の複雑なコードパスの処理におけるバグを示しています。
技術的詳細
このコミットが追加した test/bugs/bug130.go
は、以下のGo言語の機能の組み合わせをテストしています。
- インターフェースの定義:
type I interface { send(chan <- int) }
I
というインターフェースを定義し、send
というメソッドを持つことを規定しています。send
メソッドはchan <- int
型のチャネルを引数にとり、何も返しません。chan <- int
は「int型を送信専用のチャネル」であることを示します。 - 構造体とメソッドの実装:
type S struct { v int } func (p *S) send(c chan <- int) { c <- p.v }
S
という構造体を定義し、そのポインタレシーバを持つsend
メソッドを実装しています。このsend
メソッドは、S
型のv
フィールドの値を引数c
のチャネルに送信します。これにより、*S
型は暗黙的にI
インターフェースを実装します。 - インターフェース型変数への代入:
var i I = &s;
main
関数内でS
型の変数s
を作成し、そのアドレス&s
をI
インターフェース型の変数i
に代入しています。これにより、i
は*S
型の具体的な値を保持し、I
インターフェースで定義されたsend
メソッドを呼び出すことができます。 - チャネルの作成:
c := new(chan int);
int
型の値を送受信するためのチャネルを作成しています。 - インターフェースメソッドのゴルーチン起動:
go i.send(c);
これがこのテストの核心部分です。インターフェース型変数i
を介して、そのメソッドsend
を新しいゴルーチンとして起動しようとしています。
当時のGoコンパイラは、この go i.send(c)
という構文を正しく処理できませんでした。インターフェースメソッドの呼び出しは、実行時に具体的な型が決定される動的ディスパッチを伴います。これを go
ステートメントと組み合わせることで、コンパイラはゴルーチン起動時に必要なコンテキスト(どの具体的なメソッドを呼び出すか、その引数は何かなど)を正しく構築できなかったと考えられます。
test/golden.out
に記録された fatal error: getoutarg: not a func RANGE
は、この問題がコンパイラのバックエンド、特に関数呼び出しの引数処理や、コードの実行範囲(RANGE
)の解析に関連する部分で発生していたことを示唆しています。これは、Go言語の初期段階におけるコンパイラの成熟度や、特定の複雑なコードパスの処理におけるバグを示しており、このテストケースは、そのバグを再現し、将来の修正を検証するための重要なリファレンスとなりました。
コアとなるコードの変更箇所
このコミットのコアとなる変更は、新しいテストファイル test/bugs/bug130.go
の追加です。
--- a/test/bugs/bug130.go
+++ b/test/bugs/bug130.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: should run
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I interface { send(chan <- int) }
+
+type S struct { v int }
+func (p *S) send(c chan <- int) { c <- p.v }
+
+func main() {
+ s := S{0};
+ var i I = &s;
+ c := new(chan int);
+ go i.send(c);
+ sys.exit(<-c);
+}
そして、このテストが失敗することを期待して、test/golden.out
にそのエラーメッセージを追加しています。
--- a/test/golden.out
+++ b/test/golden.out
@@ -157,6 +157,10 @@ BUG: errchk: command succeeded unexpectedly: 6g bugs/bug125.go
bugs/bug129.go:6: syscall is package, not var
BUG129
+=========== bugs/bug130.go
+bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
+BUG: should run
+
=========== fixedbugs/bug016.go
fixedbugs/bug016.go:7: overflow converting constant to uint
コアとなるコードの解説
test/bugs/bug130.go
は、Go言語のコンパイラまたはランタイムにおける特定のバグを再現するための最小限のコードです。
-
インターフェース
I
の定義:type I interface { send(chan <- int) }
これは、send
という名前のメソッドを持つインターフェースを定義しています。このメソッドはint
型の値を送信するためのチャネルを引数にとります。 -
構造体
S
とそのメソッドsend
の実装:type S struct { v int } func (p *S) send(c chan <- int) { c <- p.v }
S
は単一の整数フィールドv
を持つシンプルな構造体です。*S
型に定義されたsend
メソッドは、I
インターフェースのsend
メソッドのシグネチャと一致するため、*S
型は暗黙的にI
インターフェースを実装します。このメソッドは、レシーバp
のv
の値を引数で渡されたチャネルc
に送信します。 -
main
関数内のロジック:func main() { s := S{0}; var i I = &s; c := new(chan int); go i.send(c); sys.exit(<-c); }
s := S{0};
:S
型の変数s
を初期値0
で宣言・初期化します。var i I = &s;
:I
インターフェース型の変数i
を宣言し、s
のアドレス(*S
型)を代入します。これにより、i
はS
のインスタンスをインターフェースとして参照します。c := new(chan int);
:int
型のチャネルc
を作成します。go i.send(c);
: この行がテストの核心です。 インターフェース型変数i
を介して、そのsend
メソッドを新しいゴルーチンとして起動しようとしています。当時のGoコンパイラは、この動的なメソッドディスパッチを伴うゴルーチン起動を正しく処理できず、内部エラーfatal error: getoutarg: not a func RANGE
を発生させていました。sys.exit(<-c);
:main
ゴルーチンは、c
チャネルから値を受信するまでブロックします。もしgo i.send(c)
が成功していれば、send
ゴルーチンが0
をチャネルに送信し、main
ゴルーチンは0
を受け取って正常終了するはずです。しかし、バグによりゴルーチンが起動しないため、この行は実行されず、コンパイル時または実行時にエラーが発生します。
test/golden.out
の変更は、このテストが期待通りに失敗し、特定のエラーメッセージを出力することを確認するためのものです。これは、テスト駆動開発(TDD)のアプローチに似ており、まずバグを再現するテストを作成し、そのテストが失敗することを確認してから、バグ修正に取り掛かるという流れを示唆しています。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Go言語の並行処理に関する公式ブログ記事: https://go.dev/blog/concurrency-is-not-parallelism
- Go言語のインターフェースに関する公式ブログ記事: https://go.dev/blog/interfaces
参考にした情報源リンク
- Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
- Go言語の初期のメーリングリストやバグトラッカー(当時の情報源は公開されていない可能性が高いですが、コミットメッセージの
OCL
やCL
番号は内部的な変更リスト番号を示唆しています。) - Go言語のコンパイラ設計に関する一般的な情報(Goのコンパイラは、初期にはC言語で書かれ、後にGo自身で書き直されました。このコミットの時期はC言語版コンパイラの時代です。)
- Web検索: "Go language "fatal error: getoutarg: not a func RANGE" 2008 2009" (この検索により、エラーメッセージがGoコンパイラの内部エラーであり、後のアップデートで解決されたことが確認されました。)