【Go入門】関数と可変長引数

Go
スポンサーリンク

Go言語の関数の定義を扱いましたが、予め定義した数だけの引数を扱っていました。

では、その引数に任意の数だけ渡すとなるとどうなるでしょうか。

関数でこの任意の数の引数を扱って定義するものを、可変長引数(Variadic parameter)といいます。

ここでは、この可変長引数についてみていきましょう。

スポンサーリンク

可変長引数(Variadic parameter)

Go言語では、無制限の数の引数をとる関数を定義することができます。これを可変長引数(Variadic parameter)といいます。

これまでは、次のコードのように、関数に渡す引数の数は決まっていました。

func calc(x int, y int) int {
	return x + y
}

ここでは、int型のxとyという2つの引数を渡しているわけです。

この引数の数に制限を設けないのが可変長引数です。

可変長引数を使った関数は、次のような形で定義します。

func 関数名(引数名 ...型名) 型名 {
	処理コード
}

引数に型名を指定する時に、「…」を前につけることで関数を宣言します。

具体的なコードでやってみましょう。引数の値の総和を求める関数を定義してみます。

package main

import "fmt"

func sum(n ...int) int {
	fmt.Println(n)
	fmt.Printf("%T\n", n)

	sum := 0
	for i, v := range n {
		sum += v
		fmt.Println("インデックス:", i, "値:", v, "・・・現在の合計:", sum)
	}
	return sum
}

func main() {
	x := sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
	fmt.Println("引数で渡した数の総和:", x)
}

関数名をsum()にしました。引数nをint型の可変長引数で定義しているのがわかります。

nの値と型名を確認のためにPrintln()とPrintf()で出力しています。

合計を求める関数なので、sumという変数を0で初期化して、for文を使って値を一つずつ取り出して順に加えていく処理を、sum += v で行っています。

ループ処理で、インデックス、値、その時の合計を出力して確認しています。

最後にreturnで合計の値を返しています。

これをmain関数で呼び出して、可変長引数として1から10までの数字を渡して実行しています。

実行すると次のように出力されます。

[1 2 3 4 5 6 7 8 9 10]
[]int
インデックス: 0 値: 1 ・・・現在の合計: 1
インデックス: 1 値: 2 ・・・現在の合計: 3
インデックス: 2 値: 3 ・・・現在の合計: 6
インデックス: 3 値: 4 ・・・現在の合計: 10
インデックス: 4 値: 5 ・・・現在の合計: 15
インデックス: 5 値: 6 ・・・現在の合計: 21
インデックス: 6 値: 7 ・・・現在の合計: 28
インデックス: 7 値: 8 ・・・現在の合計: 36
インデックス: 8 値: 9 ・・・現在の合計: 45
インデックス: 9 値: 10 ・・・現在の合計: 55
引数で渡した数の総和: 55

可変長引数で渡したものは、スライスになっているのがわかります。ここでは[]intのスライスです。合計値が計算されて出力されています。

スポンサーリンク

スライスの展開

今度は、可変長引数のスライスそのものを渡す場合についてみて行きます。

上のコードを次のように少し変更してみます。

package main

import "fmt"

func sum(n ...int) int {
	fmt.Println(n)
	fmt.Printf("%T\n", n)

	sum := 0
	for _, v := range n {
		sum += v
	}
	return sum
}

func main() {
	s := []int{10, 20, 30, 40, 50}
	result := sum(s...)
	fmt.Println("結果:", result)
}

sum()関数の基本的なところは先ほどと変わっていません。可変長引数での関数で、for文でのインデックスをアンダースコアに変えて利用しないことにし、ループ毎の出力を削除しただけで、計算そのものは同じです。

これをmain()関数で呼び出すのですが、変数sでスライスを定義しています。この変数をsum()関数に渡して実行するのですが、sum(s)ではなく、sum(s…)となっていることに注意です。

実行するとこうなります。

[10 20 30 40 50]
[]int
結果: 150

思った結果が出力されていると思います。このようにして、スライスは展開します。

スライスを可変長引数として渡す時は、「…」とスライスに続けて渡すということに注意です。

もし、次のように、sum(s…)ではなく、sum(s)として呼び出した場合はどうなるでしょうか?

func main() {
	s := []int{10, 20, 30, 40, 50}
	result := sum(s)
	fmt.Println("結果:", result)
}

この場合は、実行すると次のようにエラーになります。

cannot use s (type []int) as type int in argument to sum

このように、可変長引数の関数でスライスを引数として展開するには、「…」を付けて渡すことに注意しましょう。

スポンサーリンク

Pythonコードで書くと…

Pythonでの可変長引数についてやってみましょう。

Pythonでの可変長引数は、関数定義時の引数名に *や** をつけると可変長引数として扱われます。

*args、*kwargsという使われ方をすることが多いです。タプル型として渡されることになります。

Goでのコードを次のように書き換えてみました。

def sum(*args):
    print(args)
    print(type(args))

    sum = 0
    for i in args:
        sum += i
        print("現在の合計:", sum)

    return sum


def main():
    x = sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    print("引数で渡した数の総和:", x)


if __name__ == "__main__":
    main()

実行すると以下のように出力されます。

(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
<class 'tuple'>
現在の合計: 1
現在の合計: 3
現在の合計: 6
現在の合計: 10
現在の合計: 15
現在の合計: 21
現在の合計: 28
現在の合計: 36
現在の合計: 45
現在の合計: 55
引数で渡した数の総和: 55
スポンサーリンク

最後に

Go言語の関数において、可変長引数(Variadic parameter)についてみてきました。

無制限の数の引数をとる関数を定義することができるのが、可変長引数です。

func 関数名(引数名 …型名) 型名 {処理コード} のように、引数の型名を指定する時に、「…」を直前に付けて定義します。

スライスを可変長引数の関数に渡す時は、スライスの変数に続けて「…」を記述します。

Go
スポンサーリンク
CodeGraffitiをフォローする

タイトルとURLをコピーしました