[インデックス 16089] ファイルの概要
このコミットでは、go
コマンドラインツールの run
サブコマンドの動作が変更されました。具体的には、以下の3つのファイルが変更されています。
doc/go1.1.html
: Go 1.1 のリリースノートにgo run
コマンドの変更点が追記されました。src/cmd/go/doc.go
:go run
コマンドのヘルプメッセージが更新され、ファイルが指定されない場合の新しい動作が記述されました。src/cmd/go/run.go
:go run
コマンドの実際のロジックが修正され、ファイルが指定されない場合に現在のディレクトリ内の非テストGoソースファイルを自動的に実行するようになりました。
コミット
commit 2a99f2fb2a736a9a4575f937cf7af57589beba9b
Author: Jonathan Rudenberg <jonathan@titanous.com>
Date: Thu Apr 4 12:04:35 2013 +1100
cmd/go: run main package when no files are listed
Fixes 5164.
R=golang-dev, iant, adg
CC=golang-dev
https://golang.org/cl/8119049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2a99f2fb2a736a9a4575f937cf7af57589beba9b
元コミット内容
cmd/go: run main package when no files are listed
Fixes 5164.
R=golang-dev, iant, adg
CC=golang-dev
https://golang.org/cl/8119049
変更の背景
この変更は、GoのIssue 5164「cmd/go: run main package when no files are listed」を解決するために行われました。
以前の go run
コマンドは、実行するGoソースファイルを明示的に指定する必要がありました。例えば、main.go
というファイルを実行するには go run main.go
と入力する必要がありました。もしファイルが指定されなかった場合、go run: no go files listed
というエラーが発生していました。
この挙動は、特に main
パッケージのソースファイルと同じディレクトリにテストファイル(_test.go
で終わるファイル)が存在する場合に問題を引き起こしていました。例えば、go run *.go
のようにワイルドカードを使って実行しようとすると、テストファイルも含まれてしまい、go run
がエラーを返す原因となっていました。これは、go test
コマンドが引数なしで実行された場合に現在のディレクトリ内のテストファイルを自動的に見つけて実行するのと対照的で、一貫性に欠けるという指摘がありました。
このコミットは、go run
コマンドの使い勝手を向上させ、go test
と同様に、引数なしで実行された場合に現在のディレクトリ内の非テストGoソースファイルを自動的に見つけて実行できるようにすることで、この問題を解決することを目的としています。これにより、go run
は実質的に go run *.go
のような動作を、テストファイルを誤って含めることなく実現できるようになりました。
前提知識の解説
Go言語の main
パッケージと main
関数
Go言語の実行可能なプログラムは、必ず package main
と func main()
を含んでいます。
package main
: これは、そのファイルが実行可能なプログラムのエントリポイントであることを示します。func main()
: プログラムが実行される際に最初に呼び出される関数です。
go run
コマンドは、この main
パッケージと main
関数を含むGoソースファイルをコンパイルし、実行するために使用されます。
go run
コマンド
go run
コマンドは、指定されたGoソースファイルを一時的にコンパイルし、その結果生成された実行可能ファイルを即座に実行するGoツールチェーンのコマンドです。開発中に小さなプログラムを素早くテストしたり、スクリプトのように実行したりするのに便利です。通常、コンパイルされた実行可能ファイルは一時ディレクトリに作成され、実行後に削除されます。
テストファイル (_test.go
)
Go言語では、テストコードは慣習的に _test.go
というサフィックスを持つファイルに記述されます。例えば、my_package.go
のテストは my_package_test.go
に書かれます。go test
コマンドは、これらの _test.go
ファイルを自動的に認識し、テストを実行します。通常のアプリケーションコードとは分離されており、go run
や go build
で直接実行されることは意図されていません。
filepath.Glob
Go標準ライブラリの path/filepath
パッケージにある Glob
関数は、シェルが使用するパターン(ワイルドカード)に一致するファイル名を検索するために使用されます。例えば、*.go
というパターンは、現在のディレクトリにあるすべての .go
拡張子を持つファイルに一致します。
strings.HasSuffix
Go標準ライブラリの strings
パッケージにある HasSuffix
関数は、ある文字列が特定のサフィックス(接尾辞)で終わっているかどうかをチェックするために使用されます。このコミットでは、ファイル名が _test.go
で終わっているかどうかを判断するために使われています。
技術的詳細
このコミットの主要な変更点は、go run
コマンドが引数なしで呼び出された場合の動作です。
- 引数なしでの実行: 以前は、
go run
にファイルが指定されない場合、fatalf("go run: no go files listed")
というエラーで即座に終了していました。この変更により、files
スライスが空の場合、go run
は現在の作業ディレクトリ内のすべての.go
ファイルを検索するようになりました。 filepath.Glob("*.go")
の使用:path/filepath
パッケージのGlob
関数を使用して、現在のディレクトリにあるすべての.go
ファイルのリストを取得します。これにより、明示的にファイル名を指定しなくても、Goソースファイルを自動的に検出できるようになります。- テストファイルの除外: 取得した
.go
ファイルのリストから、_test.go
で終わるファイルをフィルタリングして除外します。これはstrings.HasSuffix(file, "_test.go")
を使用して行われます。これにより、go run
が誤ってテストコードをコンパイル・実行してしまうことを防ぎます。 - エラーハンドリングの改善:
filepath.Glob
がエラーを返した場合の処理が追加されました。また、フィルタリングの結果、実行可能なGoファイルが一つも見つからなかった場合にfatalf("go run: no go files found")
というエラーメッセージを出すようになりました。 - ドキュメントの更新:
doc/go1.1.html
にgo run
コマンドの変更点がGo 1.1のリリースノートとして追加され、src/cmd/go/doc.go
のヘルプメッセージも更新され、新しい動作がユーザーに明確に伝えられるようになりました。
この変更により、go run
はより柔軟になり、go run
とだけ入力することで、現在のディレクトリにある main
パッケージのプログラムを簡単に実行できるようになりました。これは、特に単一のGoファイルで構成されるスクリプトのようなプログラムを頻繁に実行する場合に便利です。
コアとなるコードの変更箇所
src/cmd/go/doc.go
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -367,9 +367,10 @@ Compile and run Go program
Usage:
-- go run [build flags] gofiles... [arguments...]
++ go run [build flags] [gofiles...] [arguments...]
Run compiles and runs the main package comprising the named Go source files.
+If no files are named, it compiles and runs all non-test Go source files.
For more about build flags, see 'go help build'.
src/cmd/go/run.go
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -8,14 +8,16 @@ import (
"fmt"
"os"
"os/exec"
+ "path/filepath"
"strings"
)
var cmdRun = &Command{
-\tUsageLine: "run [build flags] gofiles... [arguments...]\",
+\tUsageLine: "run [build flags] [gofiles...] [arguments...]\",
Short: "compile and run Go program",
Long: `
Run compiles and runs the main package comprising the named Go source files.
+If no files are named, it compiles and runs all non-test Go source files.
For more about build flags, see 'go help build'.
@@ -44,7 +46,18 @@ func runRun(cmd *Command, args []string) {
}\n\tfiles, cmdArgs := args[:i], args[i:]\n\tif len(files) == 0 {\n-\t\tfatalf(\"go run: no go files listed\")\n+\t\tallFiles, err := filepath.Glob(\"*.go\")\n+\t\tif err != nil {\n+\t\t\tfatalf(\"go run: %s\", err)\n+\t\t}\n+\t\tfor _, file := range allFiles {\n+\t\t\tif !strings.HasSuffix(file, \"_test.go\") {\n+\t\t\t\tfiles = append(files, file)\n+\t\t\t}\n+\t\t}\n+\t\tif len(files) == 0 {\n+\t\t\tfatalf(\"go run: no go files found\")\n+\t\t}\n \t}\n \tfor _, file := range files {\n \t\tif strings.HasSuffix(file, \"_test.go\") {\
コアとなるコードの解説
src/cmd/go/run.go
の runRun
関数が go run
コマンドの主要なロジックを含んでいます。
変更前のコードでは、files
スライス(実行対象のGoファイル名が格納される)が空の場合、即座に fatalf("go run: no go files listed")
というエラーを出力して終了していました。
変更後のコードでは、if len(files) == 0 { ... }
ブロックが追加され、以下の処理が行われます。
allFiles, err := filepath.Glob("*.go")
:filepath.Glob("*.go")
を呼び出し、現在のディレクトリにあるすべての.go
拡張子を持つファイル名を検索します。- 検索結果は
allFiles
スライスに格納され、エラーがあればerr
に格納されます。
if err != nil { fatalf("go run: %s", err) }
:filepath.Glob
の実行中にエラーが発生した場合(例: 無効なパターン、パーミッションの問題など)、そのエラーメッセージと共にプログラムを終了します。
for _, file := range allFiles { ... }
:allFiles
に含まれる各ファイル名に対してループ処理を行います。
if !strings.HasSuffix(file, "_test.go") { files = append(files, file) }
:- 現在のファイル名
file
が_test.go
で終わっていないかどうかをstrings.HasSuffix
でチェックします。 - もし
_test.go
で終わっていなければ(つまり、テストファイルでなければ)、そのファイル名をfiles
スライスに追加します。これにより、実行対象のファイルリストが構築されます。
- 現在のファイル名
if len(files) == 0 { fatalf("go run: no go files found") }
:- すべての
.go
ファイルを検索し、テストファイルを除外した結果、files
スライスがまだ空の場合(つまり、実行可能な非テストGoファイルが一つも見つからなかった場合)、go run: no go files found
というエラーメッセージを出力してプログラムを終了します。
- すべての
このロジックにより、go run
は引数なしで実行された際に、現在のディレクトリから適切な main
パッケージのソースファイルを自動的に見つけて実行できるようになりました。
また、src/cmd/go/doc.go
では、go run
の UsageLine
が [gofiles...]
の部分を [gofiles...]
と変更し、角括弧で囲むことでオプションであることを示しています。さらに、Long
説明に「If no files are named, it compiles and runs all non-test Go source files.」という新しい行が追加され、この新しい動作が明記されています。
関連リンク
- Go Issue 5164: https://go.dev/issue/5164
- Go CL 8119049: https://golang.org/cl/8119049
参考にした情報源リンク
- appspot.com (Vertex AI Search Grounding API Redirect): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHWc4WTjCgcqoJhPSOPz-ln5eTkjMlsfLOvnH_cWcvuIF5VqrJHa3AOzM1t48jU_H2r3SYfPTWEjkUYe9K-DyKs_pamMH1Sq7uJLx9wh3y1pYbMuWoJGa4_ZxcafQEN6vnN