[インデックス 12453] ファイルの概要
このコミットは、Go言語のコマンドラインツール go run
のエラーメッセージを改善し、よりユーザーフレンドリーにするための変更です。具体的には、go run
コマンドにGoファイルが指定されなかった場合と、main
パッケージではないGoファイルを指定した場合のエラーメッセージを修正しています。
コミット
commit 85ae6a18b5878a3fecd62ffc6887906e0c8c4d15
Author: Russ Cox <rsc@golang.org>
Date: Wed Mar 7 00:01:57 2012 -0500
cmd/go: fix run errors
$ go run
go run: no go files listed
$ go run ../../pkg/math/bits.go
go run: cannot run non-main package
$
Fixes #3168.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5755064
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/85ae6a18b5878a3fecd62ffc6887906e0c8c4d15
元コミット内容
cmd/go: fix run errors
このコミットは、go run
コマンドが以下のような状況で出力するエラーメッセージを修正します。
go run
の後にGoファイルが指定されなかった場合。 変更前: (おそらく一般的なGoツールのエラーメッセージ) 変更後:go run: no go files listed
main
パッケージではないGoファイルをgo run
で実行しようとした場合。 変更前:cannot run non-main package
変更後:go run: cannot run non-main package
この変更は、Issue #3168 を修正するものです。
変更の背景
go run
コマンドは、Go言語のソースファイルをコンパイルして実行するための便利なツールです。しかし、ユーザーが誤った使い方をした場合、出力されるエラーメッセージが必ずしも明確ではないことがありました。
特に、以下の2つのケースが問題でした。
- 引数なしでの実行:
go run
とだけ入力して実行した場合、ユーザーはGoファイルを指定し忘れたことに気づきにくい可能性がありました。より具体的なエラーメッセージを提供することで、ユーザーがすぐに問題を特定し、修正できるようにすることが目的です。 - 非
main
パッケージの実行:go run
は実行可能なプログラム(つまりmain
パッケージ)を対象としています。ライブラリパッケージなどを誤ってgo run
で実行しようとした場合、既存のエラーメッセージcannot run non-main package
は正しいものの、どのコマンドがそのエラーを出力しているのかが不明瞭でした。go run:
というプレフィックスを追加することで、エラーの発生源を明確にし、ユーザーがgo run
の正しい使い方を理解する手助けとなります。
これらの改善は、Goツールの全体的なユーザーエクスペリエンスを向上させ、開発者がより効率的に作業できるようにすることを目的としています。
前提知識の解説
Go言語のパッケージと main
パッケージ
Go言語のプログラムは「パッケージ」という単位で構成されます。パッケージは関連するGoソースファイルの集まりです。
特別なパッケージとして main
パッケージがあります。main
パッケージは、実行可能なプログラムのエントリポイント(main
関数)を含むパッケージであり、Goプログラムとして単独で実行できるのは main
パッケージのみです。ライブラリとして機能するパッケージは main
パッケージではありません。
go run
コマンド
go run
コマンドは、Goソースファイルをコンパイルし、その場で実行するためのGoツールチェーンのコマンドです。通常、開発中に小さなプログラムをテストしたり、スクリプトのようにGoプログラムを実行したりする際に使用されます。
go run
は、指定されたGoファイルを一時的にコンパイルし、生成されたバイナリを実行します。この際、指定されたファイルが main
パッケージの一部であり、main
関数を含んでいる必要があります。
fatalf
関数
Go言語のツールや内部処理でよく使われるエラー報告関数の一つです。fmt.Errorf
のようにフォーマットされた文字列を生成し、通常はプログラムを終了させる(os.Exit(1)
を呼び出すなど)動作を伴います。このコミットでは、ユーザーにエラーメッセージを表示し、プログラムの実行を停止するために使用されています。
技術的詳細
このコミットは、src/cmd/go/run.go
ファイル内の runRun
関数を変更しています。runRun
関数は go run
コマンドの実際の処理を担う部分です。
変更点は大きく2つあります。
-
Goファイルが指定されなかった場合のエラーハンドリングの追加: 変更前は、
go run
の後にファイルが指定されなかった場合、files
スライスが空になります。この場合、goFilesPackage(files)
が呼び出され、その結果としてエラーが発生する可能性はありますが、具体的な「ファイルが指定されていない」というメッセージは出ませんでした。 変更後では、files
スライスの長さが0であるかを明示的にチェックし、もし0であればfatalf("go run: no go files listed")
を呼び出して、より明確なエラーメッセージを出力するようにしました。 -
非
main
パッケージ実行時のエラーメッセージの改善:p.Name != "main"
の条件は、指定されたGoファイルがmain
パッケージではないことを検出します。 変更前はfatalf("cannot run non-main package")
と出力していました。 変更後ではfatalf("go run: cannot run non-main package")
と変更し、エラーメッセージの先頭にgo run:
というプレフィックスを追加することで、このエラーがgo run
コマンドによって出力されたものであることを明確にしています。
これらの変更は、go run
コマンドの堅牢性を高め、ユーザーがコマンドの誤用から生じる問題をより迅速に診断できるようにすることを目的としています。
コアとなるコードの変更箇所
src/cmd/go/run.go
ファイルの runRun
関数内。
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -42,12 +42,15 @@ func runRun(cmd *Command, args []string) {
i++
}
files, cmdArgs := args[:i], args[i:]
+ if len(files) == 0 {
+ fatalf("go run: no go files listed")
+ }
p := goFilesPackage(files)
if p.Error != nil {
fatalf("%s", p.Error)
}
if p.Name != "main" {
- fatalf("cannot run non-main package")
+ fatalf("go run: cannot run non-main package")
}
p.target = "" // must build - not up to date
a1 := b.action(modeBuild, modeBuild, p)
コアとなるコードの解説
変更点1: if len(files) == 0
の追加
files, cmdArgs := args[:i], args[i:]
if len(files) == 0 {
fatalf("go run: no go files listed")
}
このコードブロックは、go run
コマンドに渡された引数からGoファイルとコマンドライン引数を分離した後、Goファイルが一つも指定されていない場合に実行されます。
len(files) == 0
は、files
スライス(go run
で実行しようとしているGoファイルのリスト)が空であるかどうかをチェックします。
もし空であれば、fatalf("go run: no go files listed")
が呼び出され、go run: no go files listed
というエラーメッセージが表示されてプログラムが終了します。これにより、ユーザーはファイル指定の不足を即座に理解できます。
変更点2: fatalf
メッセージの変更
if p.Name != "main" {
- fatalf("cannot run non-main package")
+ fatalf("go run: cannot run non-main package")
}
この部分は、goFilesPackage(files)
によって解析されたパッケージ p
の名前が "main"
ではない場合に実行されます。
p.Name != "main"
は、指定されたGoファイルが実行可能な main
パッケージではないことを意味します。
以前は fatalf("cannot run non-main package")
とだけ出力していましたが、このコミットで fatalf("go run: cannot run non-main package")
に変更されました。
この変更により、エラーメッセージの冒頭に go run:
というプレフィックスが追加され、このエラーが go run
コマンドの制約によるものであることが明確になります。これにより、ユーザーはエラーの原因をより正確に把握し、適切な対応(例えば、go run
ではなく go build
や go install
を使用する、あるいは main
パッケージのファイルを指定する)を取ることができます。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
go run
コマンドのドキュメント: https://go.dev/cmd/go/#hdr-Run_compiled_Go_programs- Go言語のパッケージに関するドキュメント: https://go.dev/doc/code#packages
参考にした情報源リンク
- コミットメッセージに記載されているGoのコードレビューシステムへのリンク: https://golang.org/cl/5755064
- コミットメッセージに記載されているIssue #3168: このIssueは、コミット日付(2012年3月7日)から判断すると、現在のGitHubリポジトリのIssueトラッカーで検索される最近のIssue(例:
golang/vscode-go
のIssue #3168)とは異なる、Goプロジェクトの初期のIssueトラッカー(おそらくGoogle Codeなど)に存在していたものと考えられます。直接的なリンクは現在のGitHubリポジトリからは見つかりませんでしたが、コミット内容からgo run
コマンドのエラーメッセージに関する改善要求であったと推測されます。