Kotlin では関数も、数値や文字列などの他の値のように扱えます。
変数に関数を代入したり、関数の引数として関数を与えたり、関数の実行結果として関数を返せます。
ポイント
このような性質を持つオブジェクトを、「第一級オブジェクト」と呼びます。
関数が第一級オブジェクトとして扱われることで、便利な使い方ができます。
ここでは、その便利な使い方についてまとめます。
参考
Kotlin 言語の関数については「関数定義と使い方」にまとめています。
関数型
Kotlin の関数はオブジェクトですので、当然「型」があります。
それは、関数型で、以下のように記述します。
フォーマット
(1番目の引数の型, 2番目の引数の型, ...) -> 返り値の型
|
1 2 3 4 5 6 7 |
fun square(x: Int): Int = x * x fun main() { val funcObj: (Int) -> Int = ::square println(funcObj(2)) // 4 } |
2個のコロン「::」で関数を指定することで、第一級オブジェクトの関数を指すことができます。
高階関数
関数を引数として受け取ったり、返り値として返すような関数のことを高階関数と呼びます。
高階関数によって、関数の抽象化が可能になります。
最初に大文字が出現する位置を返す getFirstUpperCase を例に見ていきましょう。
再帰呼び出しのみで書く
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
fun getFirstUpperCase(str: String): Int { tailrec fun next(str: String, index: Int): Int = when { str.isEmpty() -> -1 str.first().isUpperCase() -> index else -> next(str.drop(1), index + 1) } return next(str, 0) } fun main() { println(getFirstUpperCase("kotlin is Good.")) // 10 } |
tailrec は、再帰呼び出しをした際にスタックを消費しないように最適化する機能です。
高階関数を使って書く
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fun first(str: String, predicate: (Char) -> Boolean): Int { tailrec fun next(str: String, index: Int): Int = when { str.isEmpty() -> -1 predicate(str.first()) -> index else -> next(str.drop(1), index + 1) } return next(str, 0) } fun getFirstUpperCase(str: String): Int { fun isUpperCase(c: Char): Boolean = c.isUpperCase() return first(str, ::isUpperCase) } fun main() { println(getFirstUpperCase("kotlin is Good.")) // 10 } |
「ある条件の最初の文字を探す」という機能を切り出すことができました。
条件を predicate で指定しています。
このように抽象化することで、他の機能などを簡単に実装することが出来るようになります。
|
1 2 3 4 5 |
fun firstG(str: String): Int { fun isG(c: Char): Boolean = c == 'G' return first(str, ::isG) } |
このように、高階関数を使うことで使いまわしが容易になり、すごくスッキリしたコードになります。