覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Kotlin - 可変長引数を扱う

Javaのメソッドで可変長引数を扱う場合は、 <型>... 仮引数名 という記述で引数の部分を記述します。

例えば、与えられた可変長の文字列群をList化して出力するメソッドなら以下の様になります。

import java.util.Arrays;

void convToListAndPrint(String... values) {
    System.out.println((Arrays.asList(values)));
}

呼び出し側のコードは以下の様になります

convToListAndPrint("Str1", "Str2", "Str3");

実行結果は以下の通りです

[Str1, Str2, Str3]

可変長引数で渡されたパラメータは 配列 として扱われています。


以下の様に可変長引数部分に 配列を渡してメソッドを呼び出すことも可能です

convToListAndPrint(new String[] {"Str1", "Str2", "Str3"});    // -> [Str1, Str2, Str3]


Kotlinにおける可変長引数

Kotlinでは可変長引数として取る引数には、vararg 修飾子をつけます。

さきほどJavaのメソッドとして書いた convToListAndPrint をKotlinで書き直すと以下の様になります。
関数のパラメータにvararg 修飾子が付いている部分も当然異なっていますが、
Arrays.asList に可変長引数として受け取ったパラメータに * を付与している部分も違います。

fun convToListAndPrint(vararg values: String) {
    println(Arrays.asList(*values))
}

Kotlinでは、可変長引数をとる関数に 配列を渡す事ができません。可変長引数で受け取った values は、配列として格納されています。
これを、可変長引数を必要とする Arrays.asList には直接渡せません。
引数の前に* を置く スプレット演算子 というもので、配列の全要素を展開した状態にします。
これにより受け渡しが可能となっています。


以下の呼び出しは可能ですが、

convToListAndPrint("Str1", "Str2", "Str3")

以下の呼び出しはできません。コンパイルエラーになります

// コンパイルエラー
val array: Array<String> = arrayOf("Str1", "Str2", "Str3", "Str4")
convToListAndPrint(array)


スプレット演算子を利用した以下の呼び出しなら可能です

val array: Array<String> = arrayOf("Str1", "Str2", "Str3", "Str4")
convToListAndPrint(*array)


また、Javaでは可変長引数のパラメータは、一番最後の引数としてしか指定できません。
以下の様なコードはコンパイルエラーになります

import java.time.LocalDate;
import java.util.Arrays;

// コンパイルエラー(可変長引数の位置が不適切)
void convToListAddDateAndPrint(String... values, LocalDate date) {
    System.out.println(Arrays.asList(values).add(date.toString()));
}


ただし、Kotlinではこの縛り無いようで?、以下のようなコードは問題ありません。

import java.time.LocalDate;
import java.util.Arrays;

fun convToListAddDateAndPrint(vararg values: String, date: LocalDate) {
    println(Arrays.asList(*values).add(date.toString()))
}

呼び出す場合は、以下のように可変長引数以外のパラメータには名前付き引数を利用する必要があるようです。
(この辺りは、私の調べが足りてないだけかも?)

convToListAddDateAndPrint( "Str1", "Str2", "Str3", date = LocalDate.now())


まとめ

KotlinでもJavaと同様に可変長引数を扱える事が分かりました。
ただし、いくつかJavaとは異なる部分があり、意識する必要があります。