Goは本質的にオプショナルパラメータやデフォルト値を関数の引数に対してサポートしていません — 各関数はそのシグネチャに記載された引数のセットのみを受け取ります。この設計上の決定は、モデルの全体的なシンプルさとコードの予測可能性に関係しています。
他の言語、例えばPythonやC++では、オプショナル/デフォルトパラメータにより関数の動作を柔軟に定義することができます。Goでは、可読性と明確さのためにこれを犠牲にしています。
APIを柔軟にしたい場合、単にデフォルト値を設定することはできません — すべてのパラメータを明示的に渡すか、回避策を使用する必要があります。これは多くのオプションをサポートすることを難しくし、オーバーロードされた関数の数の増加を引き起こす可能性があります。
Goでは、その柔軟性のために2つのアプローチを使用します:
構造体を介したアプローチの例:
type QueryOptions struct { Limit int Offset int } func QueryDB(opts QueryOptions) { if opts.Limit == 0 { opts.Limit = 10 // デフォルト } // ... } QueryDB(QueryOptions{Limit: 100})
あるいは関数オプションを使用した例:
type Config struct { Timeout int } type Option func(*Config) func WithTimeout(t int) Option { return func(cfg *Config) { cfg.Timeout = t } } func Do(opts ...Option) { cfg := Config{Timeout: 5} // デフォルト for _, o := range opts { o(&cfg) } // ... } Do(WithTimeout(10)) // オプションを持つ呼び出し Do() // デフォルトで呼び出し
主な特徴:
例えば func F(a int = 10) の関数宣言時にデフォルト値を設定できますか?
いいえ、Goではそのような書き方はできません — 必要なパラメータの厳格なリストのみが求められます。
...interface{}タイプのスライスを持つ関数を宣言し、0の引数を渡した場合はどうなりますか?
スライスは長さ0(nil)を持ち、関数は空のスライスを受け取ります。
コード例:
func PrintAll(args ...interface{}) { fmt.Println(len(args)) // パラメータを渡さなければ0 } PrintAll() // ok
Goでパラメータの数やタイプによって関数をオーバーロードできますか?
いいえ、Goでは関数のオーバーロードはサポートされていません — 異なるシグネチャを持つ重複した関数名は許可されません。
API関数には何十ものパラメータがあり、その多くは同じタイプであり、順序を間違えて誤って混乱します:
長所:
短所:
オプション構造体または関数オプションが使用され、パラメータには明示的な名前があります:
長所:
短所: