[インデックス 17083] ファイルの概要
このコミットは、Go言語の標準ライブラリであるflag
パッケージにおける変更です。具体的には、パッケージ内部で利用されていたデフォルトのFlagSet
であるcommandLine
が、外部からアクセス可能なCommandLine
としてエクスポートされるように修正されています。この変更は、src/pkg/flag/export_test.go
、src/pkg/flag/flag.go
、src/pkg/flag/flag_test.go
の3つのファイルに影響を与えています。
コミット
commit 6ac93e2ac8bb0e0eea58f691c949b81cb66b5d5d
Author: Rob Pike <r@golang.org>
Date: Thu Aug 8 11:50:58 2013 +1000
flag: export commandLine, the previously internal default FlagSet
s/commandLine/CommandLine/g
Fixes #4209.
R=golang-dev, dsymonds, bradfitz
CC=golang-dev
https://golang.org/cl/12587043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6ac93e2ac8bb0e0eea58f691c949b81cb66b5d5d
元コミット内容
flag: export commandLine, the previously internal default FlagSet
s/commandLine/CommandLine/g
Fixes #4209.
R=golang-dev, dsymonds, bradfitz
CC=golang-dev
https://golang.org/cl/12587043
変更の背景
この変更は、Goのflag
パッケージが提供するデフォルトのコマンドライン引数パーサーであるcommandLine
(内部変数)を、外部からアクセス可能なCommandLine
(エクスポートされた変数)として公開することを目的としています。コミットメッセージにあるFixes #4209
が示す通り、この変更はIssue 4209に対応するものです。
Issue 4209は、flag
パッケージのデフォルトのFlagSet
にアクセスする方法がないという問題提起でした。flag
パッケージは、グローバルな関数(例: flag.Parse()
, flag.StringVar()
など)を提供しており、これらは内部的にcommandLine
というデフォルトのFlagSet
インスタンスを操作します。しかし、このcommandLine
変数はエクスポートされていなかったため、ユーザーはflag
パッケージのグローバル関数を通じてしかデフォルトのFlagSet
を操作できませんでした。
例えば、ユーザーが独自のFlagSet
を作成し、それをデフォルトのFlagSet
として設定したい場合や、デフォルトのFlagSet
の特定のプロパティ(例: エラーハンドリングの挙動)を変更したい場合、直接commandLine
にアクセスできないことが制約となっていました。このコミットは、この制約を取り除き、より柔軟なflag
パッケージの利用を可能にするために行われました。
前提知識の解説
Go言語におけるエクスポートとアンエクスポート
Go言語では、識別子(変数名、関数名、型名など)の最初の文字が大文字であるか小文字であるかによって、その識別子がパッケージ外からアクセス可能(エクスポートされる)か、パッケージ内でのみアクセス可能(アンエクスポートされる)かが決まります。
- エクスポートされた識別子 (Exported Identifiers): 最初の文字が大文字の識別子(例:
MyVariable
,MyFunction
,MyType
)。これらは、その識別子が定義されているパッケージをインポートした他のパッケージからアクセスできます。 - アンエクスポートされた識別子 (Unexported Identifiers): 最初の文字が小文字の識別子(例:
myVariable
,myFunction
,myType
)。これらは、その識別子が定義されているパッケージ内でのみアクセス可能です。
このコミットでは、アンエクスポートされていたcommandLine
が、エクスポートされたCommandLine
に変更されています。これにより、flag
パッケージをインポートする他のパッケージからCommandLine
変数に直接アクセスできるようになります。
Go言語のflag
パッケージ
flag
パッケージは、コマンドライン引数を解析するための機能を提供します。主な機能は以下の通りです。
- フラグの定義:
flag.StringVar()
,flag.IntVar()
,flag.BoolVar()
などの関数を使って、文字列、整数、真偽値などの型のフラグを定義できます。 - フラグの解析:
flag.Parse()
を呼び出すことで、定義されたフラグとコマンドライン引数を解析し、対応する変数に値を設定します。 FlagSet
:flag
パッケージは、複数のフラグをグループ化して管理するためのFlagSet
型を提供します。これにより、サブコマンドごとに異なるフラグセットを持つアプリケーションを構築できます。デフォルトでは、flag
パッケージのグローバル関数は内部的に単一のデフォルトFlagSet
(このコミット以前はcommandLine
、以降はCommandLine
)を操作します。
FlagSet
のExitOnError
とContinueOnError
FlagSet
を作成する際に、エラーハンドリングの挙動を指定できます。
flag.ExitOnError
: フラグの解析中にエラーが発生した場合、プログラムを終了します。これがデフォルトの挙動です。flag.ContinueOnError
: フラグの解析中にエラーが発生しても、プログラムを終了せずにエラーを返します。これにより、呼び出し元がエラーを処理できます。
このコミットでは、CommandLine
がExitOnError
で初期化されていることが示されています。
技術的詳細
このコミットの主要な変更点は、flag
パッケージの内部変数commandLine
を、エクスポートされた変数CommandLine
に変更したことです。
- 可視性の変更:
commandLine
は小文字で始まるため、flag
パッケージの内部からのみアクセス可能でした。これをCommandLine
(大文字で始まる)に変更することで、他のパッケージから直接このFlagSet
インスタンスにアクセスできるようになりました。 - グローバル関数の変更:
flag
パッケージが提供するVisitAll
,Visit
,Lookup
,Set
,PrintDefaults
,NFlag
,Arg
,NArg
,Args
,BoolVar
,Bool
,IntVar
,Int
,Int64Var
,Int64
,UintVar
,Uint
,Uint64Var
,Uint64
,StringVar
,String
,Float64Var
,Float64
,DurationVar
,Duration
,Var
,Parse
,Parsed
といったグローバル関数は、これまで内部的にcommandLine
を参照していました。この変更により、これらの関数はすべてCommandLine
を参照するように修正されました。 export_test.go
の変更: テスト用のヘルパー関数であるResetForTesting
も、内部でcommandLine
を操作していましたが、これもCommandLine
を使用するように変更されました。また、以前はcommandLine
を返すためのエクスポートされた関数CommandLine()
が存在しましたが、CommandLine
変数自体がエクスポートされたため、この関数は不要となり削除されました。- テストコードの変更:
flag_test.go
内のテストコードも、CommandLine()
関数を呼び出す代わりに、直接CommandLine
変数にアクセスするように修正されています。
この変更により、ユーザーは以下のような操作が可能になります。
flag.CommandLine.SetOutput(os.Stdout)
のように、デフォルトのFlagSet
の出力先を変更する。flag.CommandLine.Usage = myCustomUsage
のように、デフォルトのFlagSet
のヘルプメッセージ表示関数をカスタマイズする。flag.CommandLine.ErrorHandling = flag.ContinueOnError
のように、デフォルトのFlagSet
のエラーハンドリングの挙動を変更する。
これは、flag
パッケージの柔軟性を高め、より高度なコマンドラインアプリケーションの構築を容易にするための重要な改善です。
コアとなるコードの変更箇所
src/pkg/flag/export_test.go
--- a/src/pkg/flag/export_test.go
+++ b/src/pkg/flag/export_test.go
@@ -12,11 +12,6 @@ import "os"
// After calling ResetForTesting, parse errors in flag handling will not
// exit the program.
func ResetForTesting(usage func()) {
- commandLine = NewFlagSet(os.Args[0], ContinueOnError)
+ CommandLine = NewFlagSet(os.Args[0], ContinueOnError)
Usage = usage
}
-
-// CommandLine returns the default FlagSet.
-func CommandLine() *FlagSet {
- return commandLine
-}
src/pkg/flag/flag.go
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -322,7 +322,7 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
// VisitAll visits the command-line flags in lexicographical order, calling
// fn for each. It visits all flags, even those not set.
func VisitAll(fn func(*Flag)) {
- commandLine.VisitAll(fn)
+ CommandLine.VisitAll(fn)
}
// Visit visits the flags in lexicographical order, calling fn for each.
@@ -336,7 +336,7 @@ func (f *FlagSet) Visit(fn func(*Flag)) {
// Visit visits the command-line flags in lexicographical order, calling fn
// for each. It visits only those flags that have been set.
func Visit(fn func(*Flag)) {
- commandLine.Visit(fn)
+ CommandLine.Visit(fn)
}
// Lookup returns the Flag structure of the named flag, returning nil if none exists.
@@ -347,7 +347,7 @@ func (f *FlagSet) Lookup(name string) *Flag {
// Lookup returns the Flag structure of the named command-line flag,
// returning nil if none exists.
func Lookup(name string) *Flag {
- return commandLine.formal[name]
+ return CommandLine.formal[name]
}
// Set sets the value of the named flag.
@@ -369,7 +369,7 @@ func (f *FlagSet) Set(name, value string) error {
// Set sets the value of the named command-line flag.
func Set(name, value string) error {
- return commandLine.Set(name, value)
+ return CommandLine.Set(name, value)
}
// PrintDefaults prints, to standard error unless configured
@@ -387,7 +387,7 @@ func (f *FlagSet) PrintDefaults() {
// PrintDefaults prints to standard error the default values of all defined command-line flags.
func PrintDefaults() {
- commandLine.PrintDefaults()
+ CommandLine.PrintDefaults()
}
// defaultUsage is the default function to print a usage message.
@@ -400,7 +400,7 @@ func defaultUsage(f *FlagSet) {
f.PrintDefaults()
}
-// NOTE: Usage is not just defaultUsage(commandLine)
+// NOTE: Usage is not just defaultUsage(CommandLine)
// because it serves (via godoc flag Usage) as the example
// for how to write your own usage function.
@@ -415,7 +415,7 @@ var Usage = func() {
func (f *FlagSet) NFlag() int { return len(f.actual) }
// NFlag returns the number of command-line flags that have been set.
-func NFlag() int { return len(commandLine.actual) }
+func NFlag() int { return len(CommandLine.actual) }
// Arg returns the i'th argument. Arg(0) is the first remaining argument
// after flags have been processed.
@@ -429,20 +429,20 @@ func (f *FlagSet) Arg(i int) string {
// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
// after flags have been processed.
func Arg(i int) string {
- return commandLine.Arg(i)
+ return CommandLine.Arg(i)
}
// NArg is the number of arguments remaining after flags have been processed.
func (f *FlagSet) NArg() int { return len(f.args) }
// NArg is the number of arguments remaining after flags have been processed.
-func NArg() int { return len(commandLine.args) }
+func NArg() int { return len(CommandLine.args) }
// Args returns the non-flag arguments.
func (f *FlagSet) Args() []string { return f.args }
// Args returns the non-flag command-line arguments.
-func Args() []string { return commandLine.args }
+func Args() []string { return CommandLine.args }
// BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag.
@@ -453,7 +453,7 @@ func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
// BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag.
func BoolVar(p *bool, name string, value bool, usage string) {
- commandLine.Var(newBoolValue(value, p), name, usage)
+ CommandLine.Var(newBoolValue(value, p), name, usage)
}
// Bool defines a bool flag with specified name, default value, and usage string.
@@ -467,7 +467,7 @@ func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func Bool(name string, value bool, usage string) *bool {
- return commandLine.Bool(name, value, usage)
+ return CommandLine.Bool(name, value, usage)
}
// IntVar defines an int flag with specified name, default value, and usage string.
@@ -479,7 +479,7 @@ func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
// IntVar defines an int flag with specified name, default value, and usage string.
// The argument p points to an int variable in which to store the value of the flag.
func IntVar(p *int, name string, value int, usage string) {
- commandLine.Var(newIntValue(value, p), name, usage)
+ CommandLine.Var(newIntValue(value, p), name, usage)
}
// Int defines an int flag with specified name, default value, and usage string.
@@ -493,7 +493,7 @@ func (f *FlagSet) Int(name string, value int, usage string) *int {
// Int defines an int flag with specified name, default value, and usage string.
// The return value is the address of an int variable that stores the value of the flag.
func Int(name string, value int, usage string) *int {
- return commandLine.Int(name, value, usage)
+ return CommandLine.Int(name, value, usage)
}
// Int64Var defines an int64 flag with specified name, default value, and usage string.
@@ -505,7 +505,7 @@ func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
// Int64Var defines an int64 flag with specified name, default value, and usage string.
// The argument p points to an int64 variable in which to store the value of the flag.
func Int64Var(p *int64, name string, value int64, usage string) {
- commandLine.Var(newInt64Value(value, p), name, usage)
+ CommandLine.Var(newInt64Value(value, p), name, usage)
}
// Int64 defines an int64 flag with specified name, default value, and usage string.
@@ -519,7 +519,7 @@ func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
// Int64 defines an int64 flag with specified name, default value, and usage string.
// The return value is the address of an int64 variable that stores the value of the flag.
func Int64(name string, value int64, usage string) *int64 {
- return commandLine.Int64(name, value, usage)
+ return CommandLine.Int64(name, value, usage)
}
// UintVar defines a uint flag with specified name, default value, and usage string.
@@ -531,7 +531,7 @@ func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
// UintVar defines a uint flag with specified name, default value, and usage string.
// The argument p points to a uint variable in which to store the value of the flag.
func UintVar(p *uint, name string, value uint, usage string) {
- commandLine.Var(newUintValue(value, p), name, usage)
+ CommandLine.Var(newUintValue(value, p), name, usage)
}
// Uint defines a uint flag with specified name, default value, and usage string.
@@ -545,7 +545,7 @@ func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
// Uint defines a uint flag with specified name, default value, and usage string.
// The return value is the address of a uint variable that stores the value of the flag.
func Uint(name string, value uint, usage string) *uint {
- return commandLine.Uint(name, value, usage)
+ return CommandLine.Uint(name, value, usage)
}
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
@@ -557,7 +557,7 @@ func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string)\
// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
// The argument p points to a uint64 variable in which to store the value of the flag.
func Uint64Var(p *uint64, name string, value uint64, usage string) {
- commandLine.Var(newUint64Value(value, p), name, usage)
+ CommandLine.Var(newUint64Value(value, p), name, usage)
}
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
@@ -571,7 +571,7 @@ func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
// Uint64 defines a uint64 flag with specified name, default value, and usage string.
// The return value is the address of a uint64 variable that stores the value of the flag.
func Uint64(name string, value uint64, usage string) *uint64 {
- return commandLine.Uint64(name, value, usage)
+ return CommandLine.Uint64(name, value, usage)
}
// StringVar defines a string flag with specified name, default value, and usage string.
@@ -583,7 +583,7 @@ func (f *FlagSet) StringVar(p *string, name string, value string, usage string)\
// StringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a string variable in which to store the value of the flag.
func StringVar(p *string, name string, value string, usage string) {
- commandLine.Var(newStringValue(value, p), name, usage)
+ CommandLine.Var(newStringValue(value, p), name, usage)
}
// String defines a string flag with specified name, default value, and usage string.
@@ -597,7 +597,7 @@ func (f *FlagSet) String(name string, value string, usage string) *string {
// String defines a string flag with specified name, default value, and usage string.
// The return value is the address of a string variable that stores the value of the flag.
func String(name string, value string, usage string) *string {
- return commandLine.String(name, value, usage)
+ return CommandLine.String(name, value, usage)
}
// Float64Var defines a float64 flag with specified name, default value, and usage string.
@@ -609,7 +609,7 @@ func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage strin
// Float64Var defines a float64 flag with specified name, default value, and usage string.
// The argument p points to a float64 variable in which to store the value of the flag.
func Float64Var(p *float64, name string, value float64, usage string) {
- commandLine.Var(newFloat64Value(value, p), name, usage)
+ CommandLine.Var(newFloat64Value(value, p), name, usage)
}
// Float64 defines a float64 flag with specified name, default value, and usage string.
@@ -623,7 +623,7 @@ func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
// Float64 defines a float64 flag with specified name, default value, and usage string.
// The return value is the address of a float64 variable that stores the value of the flag.
func Float64(name string, value float64, usage string) *float64 {
- return commandLine.Float64(name, value, usage)
+ return CommandLine.Float64(name, value, usage)
}
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
@@ -635,7 +635,7 @@ func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration
// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
// The argument p points to a time.Duration variable in which to store the value of the flag.
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
- commandLine.Var(newDurationValue(value, p), name, usage)
+ CommandLine.Var(newDurationValue(value, p), name, usage)
}
// Duration defines a time.Duration flag with specified name, default value, and usage string.
@@ -649,7 +649,7 @@ func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time
// Duration defines a time.Duration flag with specified name, default value, and usage string.
// The return value is the address of a time.Duration variable that stores the value of the flag.
func Duration(name string, value time.Duration, usage string) *time.Duration {
- return commandLine.Duration(name, value, usage)
+ return CommandLine.Duration(name, value, usage)
}
// Var defines a flag with the specified name and usage string. The type and
@@ -685,9 +685,9 @@ func (f *FlagSet) Var(value Value, name string, usage string) {
// of strings by giving the slice the methods of Value; in particular, Set would
// decompose the comma-separated string into the slice.
func Var(value Value, name string, usage string) {
- commandLine.Var(value, name, usage)
+ CommandLine.Var(value, name, usage)
}
// failf prints to standard error a formatted error and usage message and
@@ -698,9 +698,9 @@ func (f *FlagSet) failf(format string, a ...interface{}) error {
}
// usage calls the Usage method for the flag set, or the usage function if
-// the flag set is commandLine.\n+// the flag set is CommandLine.
+// the flag set is CommandLine.
func (f *FlagSet) usage() {
- if f == commandLine {
+ if f == CommandLine {
Usage()
} else if f.Usage == nil {
defaultUsage(f)
@@ -816,17 +816,19 @@ func (f *FlagSet) Parsed() bool {
// Parse parses the command-line flags from os.Args[1:]. Must be called
// after all flags are defined and before flags are accessed by the program.
func Parse() {
- // Ignore errors; commandLine is set for ExitOnError.
- commandLine.Parse(os.Args[1:])
+ // Ignore errors; CommandLine is set for ExitOnError.
+ CommandLine.Parse(os.Args[1:])
}
// Parsed returns true if the command-line flags have been parsed.
func Parsed() bool {
- return commandLine.Parsed()
+ return CommandLine.Parsed()
}
-// The default set of command-line flags, parsed from os.Args.
-var commandLine = NewFlagSet(os.Args[0], ExitOnError)
+// CommandLine is the default set of command-line flags, parsed from os.Args.
+// The top-level functions such as BoolVar, Arg, and on are wrappers for the
+// methods of CommandLine.
+var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property.
src/pkg/flag/flag_test.go
--- a/src/pkg/flag/flag_test.go
+++ b/src/pkg/flag/flag_test.go
@@ -139,7 +139,7 @@ func TestGet(t *testing.T) {
func TestUsage(t *testing.T) {
called := false
ResetForTesting(func() { called = true })
- if CommandLine().Parse([]string{"-x"}) == nil {
+ if CommandLine.Parse([]string{"-x"}) == nil {
t.Error("parse did not fail for unknown flag")
}
if !called {
@@ -215,7 +215,7 @@ func testParse(f *FlagSet, t *testing.T) {
func TestParse(t *testing.T) {
ResetForTesting(func() { t.Error("bad parse") })
- testParse(CommandLine(), t)
+ testParse(CommandLine, t)
}
func TestFlagSetParse(t *testing.T) {
@@ -311,7 +311,7 @@ func TestChangingArgs(t *testing.T) {
defer func() { os.Args = oldArgs }()
os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
before := Bool("before", false, "")
- if err := CommandLine().Parse(os.Args[1:]); err != nil {
+ if err := CommandLine.Parse(os.Args[1:]); err != nil {
t.Fatal(err)
}
cmd := Arg(0)
コアとなるコードの解説
このコミットのコアとなる変更は、flag
パッケージ全体でcommandLine
というアンエクスポートされた変数名をCommandLine
というエクスポートされた変数名に一括置換している点です。
-
src/pkg/flag/export_test.go
:ResetForTesting
関数内で、commandLine
の代わりにCommandLine
が使用されるように変更されています。これは、テスト時にデフォルトのFlagSet
をリセットする際に、新しいエクスポートされた変数を使用するためです。- 以前は
commandLine
を返すためのエクスポートされた関数CommandLine()
が存在しましたが、CommandLine
変数自体がエクスポートされたため、この関数は冗長となり削除されました。
-
src/pkg/flag/flag.go
:flag
パッケージのほとんどのグローバル関数(VisitAll
,Visit
,Lookup
,Set
,PrintDefaults
,NFlag
,Arg
,NArg
,Args
,BoolVar
,Bool
,IntVar
,Int
,Int64Var
,Int64
,UintVar
,Uint
,Uint64Var
,Uint64
,StringVar
,String
,Float64Var
,Float64
,DurationVar
,Duration
,Var
,Parse
,Parsed
)は、内部的にデフォルトのFlagSet
を操作します。これらの関数内でcommandLine
への参照がすべてCommandLine
に置き換えられています。flag.go
のファイルの末尾にあるcommandLine
変数の宣言が、CommandLine
に変更され、コメントも更新されています。これにより、CommandLine
がデフォルトのコマンドラインフラグセットであり、トップレベルの関数がそのメソッドのラッパーであることが明確に示されています。usage
関数内の比較もf == commandLine
からf == CommandLine
に変更されています。
-
src/pkg/flag/flag_test.go
:- テストコード内で
CommandLine()
関数を呼び出していた箇所が、直接CommandLine
変数にアクセスするように変更されています。これは、CommandLine()
関数が削除されたため、テストコードもそれに合わせて修正する必要があったためです。
- テストコード内で
これらの変更により、flag
パッケージのユーザーは、デフォルトのFlagSet
に直接アクセスし、その挙動をより細かく制御できるようになりました。これは、flag
パッケージの柔軟性と使いやすさを向上させる重要な改善です。
関連リンク
- Go Issue 4209: https://golang.org/issue/4209
- Gerrit Change-Id: https://golang.org/cl/12587043
参考にした情報源リンク
- Go言語の
flag
パッケージ公式ドキュメント: https://pkg.go.dev/flag - Go言語の識別子のエクスポートに関する公式ドキュメント: https://go.dev/ref/spec#Exported_identifiers
- Go言語のIssueトラッカー (Issue 4209の詳細): https://github.com/golang/go/issues/4209
- Go言語のGerritコードレビューシステム (CL 12587043の詳細): https://go-review.googlesource.com/c/go/+/12587043