1. 概要

このクイックチュートリアルでは、Kotlinの関数に可変数の引数を渡す方法を学習します。 また、Kotlinを使用して配列をvarargに変換する方法についても説明します。

最後に、これらすべてがバイトコードレベルでどのように表されるかを見ていきます。

2. Varargs

関数に可変数の引数を渡すには、varargパラメーターを使用してその関数を宣言する必要があります。

fun sum(vararg xs: Int): Int = xs.sum()

これは、sum()関数が0個以上の整数を受け入れることができることを意味します。 例えば:

val zeroNumbers = sum()
assertEquals(0, zeroNumbers)

assertEquals(2, sum(2))
assertEquals(12, sum(2, 4, 6))

上に示したように、vararg引数に0個以上のパラメーターを渡すことができます。

関数本体の内部では、varargパラメーターを配列として扱うことができます。

fun <T> printAll(vararg ts: T) {
    ts.forEach { println(it) }
}

参照型のvarargの場合、varargパラメーターはその参照型のArrayとして扱われます。 たとえば、上記の例では、 ts パラメータは、としてアクセス可能になります配列関数本体で。 次の例では、同様に、 配列

fun printStrings(vararg vs: String) {
    vs.forEach { println(it) }
}

ただし、プリミティブ型の場合、varargパラメーターは*Array特殊配列型のように機能します。 。 たとえば、 和() 関数、 vararg パラメータは IntArray 関数本体で。

3. 制限事項

各関数は最大で1つのvarargパラメーターを持つことができます。 複数のvarargパラメーターを使用して関数を宣言すると、Kotlinコンパイラーは次のエラーで失敗します。

Kotlin: Multiple vararg-parameters are prohibited

他の多くのプログラミング言語とは異なり、varargパラメーターを最後のパラメーターとして宣言する必要はありません

fun createUser(vararg roles: String, username: String, age: Int) {
    // omitted
}

ただし、 vararg が最後に宣言されたパラメーターでない場合は、あいまいさを避けるために、他のパラメーターを名前で渡す必要があります。

createUser("admin", "user", username = "me", age = 42)

そうしないと、コンパイラはエラーで失敗します。

4. スプレッド演算子

Kotlinに既存の配列インスタンスがあり、それをvarargを受け入れる関数に渡したい場合があります。そのような状況では、配列を vararg に分解するには、次を使用できます。スプレッド演算子:

val numbers = intArrayOf(1, 2, 3, 4)
val summation = sum(*numbers)
assertEquals(10, summation)

numbers配列変数の後ろにある“ *”はspread演算子です。

5. バイトコード表現

内部では、KotlinはそのvarargsをJavavarargsに変換します。 これを確認するために、kotlincを介してKotlinソースコードをコンパイルしましょう。

$ kotlinc Vararg.kt

その後、javapを介して生成されたバイトコードを確認できます。

$ javap -c -p -v com.baeldung.varargs.VarargKt
  public static final int sum(int...);
    descriptor: ([I)I
    flags: (0x0099) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_VARARGS
  // truncated

上記のように、 vararg パラメータは、Javaではvarargとして定義されています。 また、 ACC_VARARGS フラグは、関数が可変長パラメーターを受け入れることを指定します。

さらに、スプレッド演算子を使用する場合:

val numbers = intArrayOf(1, 2)
sum(*numbers)

KotlinはArrays.copyOf(array、length)メソッドを使用して、最初に拡散配列のコピーを作成します。 次に、新しい配列をvarargパラメーターとして渡します。

12: aload_0 // loads the int[]
13: dup
14: arraylength
15: invokestatic  #71   // Method java/util/Arrays.copyOf:([II)[I
18: invokestatic  #72   // Method sum:([I)I

インデックス13と14は、2つのパラメータをオペランドスタックにロードし、それらを Arrays.copyOf(int []、int)メソッドに渡します。 基本的に、元の配列から新しい配列にすべての要素をコピーし、コピーした要素を sum()関数に渡します。

Javaでは、varargパラメーターを最後のパラメーターとして宣言する必要があります。 したがって、Kotlinの最後のパラメーターを除く任意の位置で vararg パラメーターを宣言すると、次のようになります。

fun createUser(vararg roles: String, username: String, age: Int) {
    // omitted
}

コンパイラはその特定のvarargを単純な配列に変換します

public static final void createUser(java.lang.String[], java.lang.String, int);
    descriptor: ([Ljava/lang/String;Ljava/lang/String;I)V
    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL

ご覧のとおり、Kotlinコンパイラは「varargroles:String」を、予想される「String…」構文ではなく「String[]」に変換しました。

6. 結論

この短いチュートリアルでは、Kotlinでvarargパラメーターがどのように機能するかを学びました。 さらに、spread演算子を使用して、Kotlinの既存の配列タイプをvarargに変換する方法を確認しました。

いつものように、すべての例はGitHubから入手できます。