#20 Goで学ぶ関数の応用(デフォルト引数・可変長引数)の基本
Pythonを触ったことがある人なら、関数を定義するときに「引数を省略したらこの値を使う」というデフォルト引数を書いた経験があるかもしれません。ところが、Goで同じ書き方をしようとすると、そんな構文はどこにもないことに気づきます。今回は、Goに「デフォルト引数」がない理由と、その代わりにどう書けばよいのかを紹介します。あわせて、渡す個数を自由に変えられる「可変長引数」についても解説します。
Goにはデフォルト引数がない
PythonやJavaScript、C++などでは、関数の引数に初期値をあらかじめ設定しておく「デフォルト引数」という仕組みがあります。呼び出し側が値を渡さなければ、その初期値が自動的に使われる、というものです。
ところがGoの設計方針は「言語仕様をできるだけシンプルに保つ」ことを重視しており、デフォルト引数の構文はあえて用意されていません。同じように、同じ関数名で引数の型や数が違うバージョンを複数定義できる「関数オーバーロード」もGoには存在しません。慣れないうちは不便に感じるかもしれませんが、これはGoが「関数を読んだときに、何が起きるか一目でわかること」を大事にしているためです。
可変長引数(...構文)の使い方
デフォルト引数はありませんが、「引数の個数を呼び出し側が自由に決められる」可変長引数はGoにもちゃんと用意されています。型の前に...を付けるだけです。
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(sum()) // 0
fmt.Println(sum(1, 2)) // 3
fmt.Println(sum(1, 2, 3)) // 6
}
関数の中では、numsはint型のスライス(可変長の配列のようなもの)として扱われます。引数を1つも渡さなければ空のスライスになるため、上のようにsum()を呼んでもエラーにはなりません。標準ライブラリのfmt.Printlnも、実はこの可変長引数を使って実装されています。
すでにあるスライスを渡したいとき
可変長引数の関数に、すでに用意したスライスをそのまま渡したい場合は、変数の後ろに...を付けます。
nums := []int{4, 5, 6}
fmt.Println(sum(nums...)) // 15
デフォルト引数の代わりになる書き方
では「引数を省略したら初期値を使いたい」場合、Goではどうするのでしょうか。よく使われる方法を2つ紹介します。
1. ゼロ値をデフォルトとして扱う
Goの変数には、宣言しただけで自動的に入る「ゼロ値」があります(数値なら0、文字列なら空文字、といった具合です)。これを利用して、関数の内部で「値が渡されなかった(=ゼロ値のまま)場合はこの値を使う」と判定する方法があります。
func greet(name string) string {
if name == "" {
name = "ゲスト"
}
return "こんにちは、" + name + "さん"
}
2. オプション構造体パターン
設定項目が多い関数では、引数をひとつずつ並べる代わりに「設定をまとめた構造体(複数のデータをひとまとめにした型)」を渡す方法がよく使われます。呼び出し側は必要な項目だけを指定できるので、デフォルト引数に近い使い勝手になります。
type ServerOptions struct {
Port int
Timeout int
}
func NewServer(opts ServerOptions) {
if opts.Port == 0 {
opts.Port = 8080 // デフォルト値
}
if opts.Timeout == 0 {
opts.Timeout = 30
}
// ここでサーバーを起動する処理を書く
}
func main() {
NewServer(ServerOptions{Port: 3000}) // Timeoutは自動で30になる
}
この書き方は「オプション構造体パターン」と呼ばれ、Goの実務コードでもよく見かけます。関数オーバーロードが使えない代わりに、こうした構造体や可変長引数を組み合わせて柔軟性を確保する、というのがGoらしい発想です。
まとめ
Goには、他の言語にあるデフォルト引数や関数オーバーロードの構文がありません。しかしそれは機能が足りないというより、「関数の挙動を呼び出し側からも読みやすくする」というGoの設計思想の表れです。可変長引数の...構文や、ゼロ値・オプション構造体パターンを使いこなせば、他言語のデフォルト引数と同じような柔軟さを実現できます。最初は少し遠回りに感じるかもしれませんが、慣れてくるとコードの意図が読み取りやすくなるメリットを実感できるはずです。
関連記事
本ページはプロモーションを含みます。
参考書籍(PR)
Goをもっと学びたい方には「Go言語入門」がおすすめです。
コメント
コメントを投稿