既存関数を渡す仕組みがより柔軟に
関数型引数に対して、既存関数を::によって渡す仕組みが、バージョン1.4でより柔軟になりました。本節では、その変更点4個をまとめて紹介します。
デフォルト値を含む関数
まず、関数型引数のシグネチャが引数なしの場合、デフォルト値とともに引数が定義された関数を渡せるようになりました。つまり、シグネチャの引数定義の不一致でもデフォルト値があれば問題なく動作するということです。
例えば、リスト14の(1)の関数execNoParamProcessor()があるとします。この関数の引数であるprocessorには、引数がありません。
fun execNoParamProcessor(processor: () -> Int) { // (1) val ans = processor() println("計算結果: ${ans}") } fun multiply2NumWithDefault(num1: Int = 2, num2: Int = 3): Int { // (2) return num1 * num2 }
このexecNoParamProcessor()を実行する際に、次のように、リスト14の(2)の関数multiply2NumWithDefault()を渡せます。
execNoParamProcessor(::multiply2NumWithDefault)
戻り値がある関数
次は戻り値の不一致です。関数型引数のシグネチャが戻り値なし、すなわち、Unit型の場合、戻り値がある関数を渡しても問題なく動作するようになりました。
例えば、リスト15の(1)の関数execUnitProcessor()があるとします。この関数の引数であるprocessorは戻り値のない、すなわち、戻り値がUnit型の関数です。
fun execUnitProcessor(processor: (num1: Int, num2: Int) -> Unit) { // (1) processor(5, 6) } fun multiply2Num(num1: Int, num2: Int): Int { // (2) val ans = num1 * num2 println("計算結果: ${ans}") return ans }
このexecUnitProcessor()を実行する際に、次のように、リスト15の(2)のmultiply2Num()関数を渡しても問題なく動作します。
execUnitProcessor(::multiply2Num)
可変長引数の関数
次に、関数型引数のシグネチャとして、データ型が同じで引数の個数が違うだけの場合、可変長引数の関数を渡せるようになりました。
例えば、リスト16の(1)~(3)の引数processorのシグネチャは、第2引数以降のInt型引数の個数が違うだけの構造となっています。
fun doNoIntArgs(processName: String, processor: (className: String) -> Unit) { // (1) println("${processName}を実行します。") processor("い") } fun doOneIntArgs(processName: String, processor: (className: String, score: Int) -> Unit) { // (2) println("${processName}を実行します。") processor("ろ", 4) } fun doTwoIntArgs(processName: String, processor: (className: String, score1: Int, score2: Int) -> Unit) { // (3) println("${processName}を実行します。") processor("め", 4, 8) } fun showClassScore(className: String, vararg scores: Int) { // (4) println("${className}組の合計は${scores.sum()}点です。") }
これらの関数を実行する際、リスト16の(4)の可変長引数(vararg引数)の関数showClassScore()を用意して、次のように引数processorとして渡せるようになりました。
doNoIntArgs("doNoIntArgs", ::showClassScore) doOneIntArgs("doOneIntArgs", ::showClassScore) doTwoIntArgs("doTwoIntArgs", ::showClassScore)
suspend関数型引数
最後に紹介するのが、関数型引数がsuspend関数の場合です。例えば、リスト17の(1)のような関数execIntArraySuspendProcessor()があるとします。
fun execIntArraySuspendProcessor(processor: suspend (array: IntArray) -> Int) { // (1) : } fun multiplyArray(array: IntArray): Int { // (2) : }
このexecIntArraySuspendProcessor()に引数として渡す関数として、リスト17の(2)のように、suspendではない関数multiplyArray()を想定します。この場合でも、次のように、execIntArraySuspendProcessor()の引数として指定することが可能になりました。
execIntArraySuspendProcessor(::multiplyArray)
suspend関数型引数へのsuspendでない関数の適用の拡充
関数型引数に渡せる関数のバリエーションに関して、バージョン1.4での拡張は以上の4点ですが、前項で紹介したsuspend関数型引数にsuspendではない関数を渡すパターンが、バージョン1.6でさらに拡充されました。まず、リスト18のように、suspendではないラムダ式も記述できるようになりました。
execIntArraySuspendProcessor { : }
また、リスト19のように、suspendではない無名関数を代入した変数を引数として渡すことも可能になりました。
val processor = fun(array: IntArray): Int { : } execIntArraySuspendProcessor(processor)