はじめに
この記事は第5回Kotlin勉強会@Sansanの発表で使用した内容です。
自己紹介
- たろう @ngsw_taro
- エムスリー株式会社のAndroidエンジニア
- Kotlinエバンジェリスト(自称)
- 著書「Kotlinスタートブック」
もくじ
- 関数参照
- レシーバが未定のメソッド参照
- レシーバが確定のメソッド参照
- プロパティも関数
1. 関数参照
関数オブジェクト
- Kotlinでは定義済みの関数のオブジェクトを得ることができる
- 関数オブジェクトを変数に代入したり、別の関数の引数に渡したり、持ち回して便利に使える。
- 必ずしもオブジェクトではない(ヒント: インライン関数)
コード例
// 普通の関数
fun succ(n: Int): Int = n + 1
// 関数オブジェクトを取得し、変数に代入
val myFunc: (Int)->Int = ::succ
// ^^^^^^^^^^ 関数型
// メソッド呼び出しによる元の関数の計算を実行
myFunc.invoke(5) //=> 6
// 演算子オーバロードによる関数らしい記述
myFunc(7) //=> 8
応用例
// 高階関数の引数に「関数参照」を渡す
listOf(1, 2, 3).map(::succ) //=> [2, 3, 4]
// ラムダ式を使えば同じ
listOf(1, 2, 3).map { succ(it) } //=> [2, 3, 4]
- ラムダ式は、文を手続き的に記述していく
- 関数参照は、宣言的な記述になる
2. レシーバが未定のメソッド参照
メソッド参照
- メソッドのオブジェクトも取得できる
- この場合は、レシーバが未定
// 「型::メソッド名」という書式で取得
val foo: String.()->String = String::reversed
// ^^^^^^^^^^^^^^^^^ 関数型
// メソッドっぽく呼び出せる
"Kotlin".foo() //=> niltoK
拡張関数もOK
fun String.bold(): String = "**$this**"
val baz: String.()->String = String::bold
"Sansan".baz() //=> **Sansan**
普通の関数型にもなるよ
-
A.(B)->C
という型は、(A, B)->C
と同じっぽい
fun String.bold(): String = "**$this**"
// 型どっちでもOK
val aaa: String.()->String = String::bold
val bbb: (String)->String = aaa
// 呼び出し方どっちでもOK
"hoge".aaa() //=> **hoge**
aaa("fuga") //=> **fuga**
高階関数で効果を発揮
"Hello".let { it.bold() }
"Hello".let(String::bold)
もしString.()->String
が(String)->String
とみなせなかったら、2行目の書き方がNGです。
3. レシーバが確定のメソッド参照
Bound Function Reference
- bound = 束縛された
- → レシーバが確定してるメソッド参照
- Kotlin 1.1から使用できる
コード例
// 「オブジェクト::メソッド名」の書式で取得
val succ: (Int)->Int = 1::plus
succ(5) //=> 6
userRepository.findById(123L)
?.let { user -> user.copy(blocked = true) }
?.let(userRepository::update)
4. プロパティも関数
プロパティも関数として扱える
val prop: KProperty1<String, Int> = String::length
prop.get("Taro") //=> 4
val func: (String) -> Int = prop
func("Taro") //=> 4
高階関数で効果を発揮
listOf("foo", "wa").map { it.length } // => [3, 2]
listOf("foo", "wa").map(String::length) // => [3, 2]
もしKProperty1<String, Int>
が(String)->String
とみなせなかったら、2行目の書き方がNGです。
まとめ
- 関数オブジェクトを使うと宣言的な記述ができる
-
::hoge
: 関数参照 -
Foo::bar
: メソッド参照 -
foo::bar
: レシーバ固定メソッド参照 (Bound Function Reference) - プロパティも関数オブジェクトになれる
- 次に見るべきスライド?(ネタ枠)