関数型引数の渡し方
Kotlinの関数は、その引数に関数を受け取ることが可能です。このような関数を、高階関数(Higher-Order Functions)といい、関数である引数を、関数型(Function Types)引数といいます。
関数型引数定義
例えば、前回の記事のリスト9で紹介したMutableMapオブジェクトであるfruitListのforEach()メソッドは、その引数として関数を受け取るようになっており、その定義は、リスト6のようになっています。引数であるactionの型として定義されている「(Map.Entry<K, V>) -> Unit」が関数型を表し、()内が引数の型、->の先が戻り値の型を表します。結果、actionは、Map.Entry<K, V>型の引数を1個受け取り、戻り値がない関数、ということになります。
forEach(action: (Map.Entry<K, V>) -> Unit)
ラムダ式の引数の分割宣言
このforEach()の引数として前回の記事のリスト9で紹介したコードは、ラムダ式であり、本来ならば引数をひとつ定義し、リスト7のコードとなるはずです。(1)でMap.Entry<K, V>型の引数elementを定義し、(2)でそのプロパティのkeyとvalueを利用しています。
fruitList.forEach { element -> // (1) println("${element.key}のフルーツは${element.value}です") // (2) }
これが、バージョン1.1から分割宣言を利用できるようになり、前回の記事のリスト9のようなコードが可能になりました。
無名関数
ところで、リスト7のラムダ式のように、関数型引数に渡す値として、関数定義を直接記述するものを、関数リテラル(Function Literals)と言います。関数リテラルには、ラムダ式の他に、無名関数があります。
例えば、リスト8のような関数定義があるとします。この関数execIntArrayProcessor()の引数は関数型となっており、整数配列を引数として何らかの計算を行い、整数をリターンするものです。
fun execIntArrayProcessor(processor: (array: IntArray) -> Int) { val array = intArrayOf(3, 5, 7, 9) val ans = processor(array) println("計算結果: ${ans}") }
このexecIntArrayProcessor()の引数にラムダ式を渡すこともできます。一方、無名関数を渡すとなると、リスト9のコードの通りになります。
execIntArrayProcessor(fun(array: IntArray): Int { return array.sum() })
既存の関数を渡す方法
さらに、リテラルではなく、既存の関数を渡すこともできます。例えば、リスト10の関数sumArray()があるとします。
fun sumArray(array: IntArray): Int { return array.sum() }
このsumArray()の関数シグネチャは、リスト8のexecIntArrayProcessor()の関数型引数processorのシグネチャと一致します。ということは、この関数を引数として指定することが可能であり、その場合は、リスト11のように、::関数名を引数として渡します。
execIntArrayProcessor(::sumArray)
メソッドを渡す方法
この::を利用して関数型引数に値を渡せるものとして、オブジェクトのメソッドを渡せるように、バージョン1.1で変更になりました。
例えば、リスト12のクラスArrayProcessorがあるとします。メソッドsubtractArray()のシグネチャは、リスト10のsumArray()関数同様に、execIntArrayProcessor()の関数型引数processorのシグネチャと一致します。
class ArrayProcessor { fun subtractArray(array: IntArray): Int { // (1) : } fun executeArrayProcessorBySubtract() { execIntArrayProcessor(::subtractArray) // (2) } }
このArrayProcessorクラスのメソッドを引数としてexecIntArrayProcessor()を実行する場合は、リスト13のコードのように、クラスインスタンスの変数名::メソッド名を引数として渡します。
val arrayProcessor = ArrayProcessor() execIntArrayProcessor(arrayProcessor::subtractArray)
クラス内でのthisは不要に
では、subtractArray()を、同じクラス内から関数型引数として渡す場合はどのようになるかのコード例が、リスト12の(2)です。これは、本来、変数名::メソッド名の変数名部分をthisと記述し、次のコードとしていました。このthisの記述が、バージョン1.2で不要となり、(2)のようにメソッド名の指定だけで済むようになりました。
execIntArrayProcessor(this::subtractArray)